NHibernate Pitfalls: Bags and Join

This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

If you have an entity with a non-lazy loaded bag collection that I fetched using a join, you will get an incorrect number of items when you query a list of this entity: NHibernate will return as many elements as contained by the child table referenced by the bag, plus one for every item in the master table that does not have any child. This happens because NHibernate misinterprets the returned record set.

There are two solutions: either switch to a set, or apply a DistinctRootTransformer:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <hibernate-mapping default-lazy="false" namespace="SomeNamespace" assembly="SomeAssembly" xmlns="urn:nhibernate-mapping-2.2">
   3:     <class name="Order" lazy="false" table="`ORDER`">
   4:         <id name="OrderId" access="property" column="`ORDER_ID`">
   5:             <generator class="hilo" />
   6:         </id>
   7:         <property name="Customer" type="String" column="`CUSTOMER`" length="50" />
   8:         <set cascade="all-delete-orphan" inverse="true" lazy="false" fetch="join" name="Details">
   9:             <key column="`ORDER_ID`" />
  10:             <one-to-many class="OrderDetail" />
  11:         </set>
  12:     </class>
  13: </hibernate-mapping>
   1: //LINQ: no need for the result transformer
   2: var orders3 = session.Query<Order>().Fetch(o => o.Details).ToList();
   3: //HQL
   4: var orders1 = session.CreateQuery("from Order o join fetch o.Details").SetResultTransformer(Transformers.DistinctRootEntity).List();
   5: //Criteria
   6: var orders2 = session.CreateCriteria<Order>().SetResultTransformer(Transformers.DistinctRootEntity).List();

Interestingly, if you use LINQ you don’t have this problem.

Bookmark and Share


No Comments