UpTheCreek
UpTheCreek

Reputation: 32401

NHibernate returning duplicate object in child collections when using Fetch

When doing a query like this (using Nhibernate 2.1.2):

 ICriteria criteria = session.CreateCriteria<MyRootType>()
                .SetFetchMode("ChildCollection1", FetchMode.Eager)
                .SetFetchMode("ChildCollection2", FetchMode.Eager)
                .Add(Restrictions.IdEq(id));

I am getting multiple duplicate objects in some cartesian fashion. E.g. if ChildCollection1 has 3 elements, and ChildColection2 has 2 elements then I get results with each element in ChildColection1 one duplicated, and each element in ChildColection2 triplicated! This was a bit of a WTF moment for me...

So how to do this correctly?


Update:

As per Felice's suggestion, I tried using the DistinctRootEntity transformer, but this is still returning duplicates. Code:

ICriteria criteria = session.CreateCriteria<MyRootType>()
                .SetFetchMode("ChildCollection1", FetchMode.Eager)
                .SetFetchMode("ChildCollection2", FetchMode.Eager)
                .Add(Restrictions.IdEq(id));

 criteria.SetResultTransformer(Transformers.DistinctRootEntity);

 return criteria.UniqueResult<MyRootType>();

Upvotes: 16

Views: 5726

Answers (5)

Guillermo Guti&#233;rrez
Guillermo Guti&#233;rrez

Reputation: 17869

Try using Futures:

ICriteria criteriaFuture1
    = session.CreateCriteria<MyRootType>()
        .SetFetchMode("ChildCollection1", FetchMode.Eager)
        .Add(Restrictions.IdEq(id))
        .SetResultTransformer(Transformers.DistinctRootEntity)
        .FutureValue<MyRootType>();
 ICriteria criteriaFuture2
    = session.CreateCriteria<MyRootType>()
        .SetFetchMode("ChildCollection2", FetchMode.Eager)
        .Add(Restrictions.IdEq(id))
        .SetResultTransformer(Transformers.DistinctRootEntity)
        .FutureValue<MyRootType>();

 return criteriaFuture1.Value;

Upvotes: 2

JoshBerke
JoshBerke

Reputation: 67128

What were you mapping your collection as? If your using a bag for example you will get duplicates. You can use a set instead and you won't get duplicates.

Upvotes: 3

schmmd
schmmd

Reputation: 19478

I am not using NHibernate (rather, regular 'ol Hibernate), but in the Java version of Hibernate you can define One-To-Many collections as either Lists or Sets. If you define them as Sets you will not get duplicates. Surprisingly enough, this happens without overriding equals(). Unfortunately, I have the same problem and I want Lists so I can integrate with Wicket but no duplicates...

Upvotes: 3

Mauricio Scheffer
Mauricio Scheffer

Reputation: 99750

You're doing a cartesian product here. Don't. Instead, fetch each collection separately.

BTW: this isn't something NHibernate-specific, the same applies to any ORM in any platform, or even pure SQL without any ORM at all. In general, you don't want to fetch N*M rows when you can fetch N+M instead.

Upvotes: 11

Felice Pollano
Felice Pollano

Reputation: 33272

You can select single distinct results by specifying SetResultsTransformer(Transformers.DistinctRootEntity);

Upvotes: 15

Related Questions