问题
I have an object model like this:
class EntityA
{
...
IList<EntityB> BList;
...
}
class EntityB
{
...
IList<EntityC> CList;
}
I have to fetch all the colelctions (Blist in EntityA and CList in EntityB), because if they all will be needed to make some operations, if i don't eager load them i will have the select n+1 problem. So the query was this:
select a from EntityA a left join fetch a.BList b left join fetch b.CList c
The fist problem i faced with this query, was the return of duplicates from the DB, i had EntityA duplicates, because of the left join fetch with BList. A quick read through the hibernate documentation and there were some solutions, first i tried the distinct keyword that supposelly wouldn't replicate the SQL distinct keyword except in some cases, maybe this was one of those cases because i had a SQL error saying that i cannot select distict text columns (column [Observations] in EntityA table). So i used one of the other solutions:
query.SetResultTransformer(new DistinctRootEntityResultTransformer());
This worked fine. But the result of the operations were still not passing the tests. I checked further and i found out that now there were duplicates of EntityB, because of the left join fetch with CList.
The question is, how can i use the distinct in a second level collection? I searched and i only find solutions for the root entity's direct child collection, but never for the second level child collections...
Thank you for your time
回答1:
You cannot accomplish what you want in a simple manner. I believe that it's the left join fetch of C that causes the duplicates. The generated query is something like this:
select a
left join a.b b
left join b.c c
and the rows returned by the db will be like this:
1: a1 | b1 | c1
2: a1 | b1 | c2
3: a1 | b2 | c3
4: a1 | b2 | c4
...
Althouh you already have filtered the root entity duplicates (the A's), due to the outer join on C, the DB needs to return repeated entries for the B table for each of C's entry.
A simple way to solve this is to filter the items through a utility collection. Depending on your Entity requirements, you may also use a HashSet
so it automatically filters them out.
回答2:
Use an ISet
instead of an IList
(and map it as a set offcourse, instead as a bag).
A Set does not allow duplicate entities.
回答3:
I encountered the same problem and was not able to solve the duplicate issue through hql. However, I created IEqualityComparer for all collections and did Disinct() on each Collection to eliminate duplicates on top of the hql result.
来源:https://stackoverflow.com/questions/2217808/nhibernate-distinct-results-in-second-level-collection