I have a small problem with multiple instances of the same object after a join to an other table. For testing I create one Store
with two Products
(ManyToMany-Relation). The following snippet hopefully describes my problem.
var preResult = _session.QueryOver<Store>().List(); // One store
Product productAlias = null;
var result = _session.QueryOver<Store>()
.JoinAlias(s => s.Products, () => productAlias)
.List(); // Two instances of the same store
I even think this behavior is correct but how can I prevent the multiple instances? Is it possible within the query?
Just for information why I need to make this unnecessary join: I want to extend the query according to different critirias, similar to this:
Product productAlias = null;
var query = _session.QueryOver<Store>().JoinAlias(s => s.Products, () => productAlias);
if (!string.IsNullOrWhiteSpace(criteria.ProductName))
{
query.Where(Restrictions.On(() => productAlias.Name).IsInsensitiveLike(criteria.ProductName));
}
if (criteria.ProductType != null)
{
query.Where(s => productAlias.Type == criteria.ProductType);
}
var result = query.List();
Here I ran into different problems, depending on the criterias.
Let's split solution into two queries.
- Top one
QueryOver<Store>()
will be correctly returning just a distinct list. And what's more, by design it will support paging (Take()
,Skip()
). - The inner one, will be returning just a list of Store IDs, which fully meet whatever criteria...
The result SQL will look like this
SELECT ... // top one
FROM Store
WHERE StoreID IN ( SELECT StoreID ...) // inner one
Inner
Let's start with the inner select, the NHibernate detached QueryOver
:
Store storeAlias = null;
Product productAlias = null;
// detached query, resulting in a set of searched StoreID
var subQuery = QueryOver.Of<Store>(() => storeAlias)
.JoinAlias((s) => s.Products, () => productAlias)
.Select((s) => s.ID); // ID projection
if (!string.IsNullOrWhiteSpace(criteria.ProductName))
{
subQuery.Where(Restrictions.On(() => productAlias.Code)
.IsInsensitiveLike(criteria.ProductName));
}
Top
Once we have filtered the Store we can use this subquery in top one
var query = session.QueryOver<Store>()
// IN clause
.Where(Subqueries.PropertyIn("ID", subQuery.DetachedCriteria))
.Skip(100)
.Take(50) // paging over already distinct resultset
;
var result = query.List<Store>();
And now we can apply whatever filter to inner query, and get list of Store IDs which do meet filter criteria... while working with top query, which is distinct...
Try using Transformers.DistinctRootEntity
in your scenario to eliminate the cartesian product.
Product productAlias = null;
var query = _session.QueryOver<Store>()
.JoinAlias(s => s.Products, () => productAlias)
query = query.TransformUsing(Transformers.DistinctRootEntity);
var result = query.List();
来源:https://stackoverflow.com/questions/14076217/preventing-multiple-instance-after-inner-join