ISession.Get<T> on an entity with multiple 'bags' results in cartesian product when populating the bags/collections
Description
Situation: I have a class 'Customer'. This class Customer has 2 collections: one collection for items of type 'Item1' and one collection for items of type 'Item2'. I have mapped these 2 collections as 'bags' in my mapping file. These collections are not lazily loaded.
Suppose I have, in the DB a Customer object which has 3 records in the related Item1 table, and 2 records in the related Item2 table. When I retrieve this customer using ISession.Get<Customer>(id), NHibernate returns me a Customer object which has 3 items for collection Item1 and 2 items for collection Item2, if the fetch-mode for these 2 collections is set to 'select'.
When I change the fetch-mode for these 2 collections to 'join' instead, and I retrieve the same Customer object (using ISession.Get<Customer>(id)), that Customer-object suddenly contains 6 items in collection Item1 and 6 items in the collection Item2. The query that is generated by NHibernate however, looks ok and returns the correct results. It just seems to be that NHibernate creates to many objects (in fact, objects are being duplicated).
When I leave the fetch-mode set to 'join', and I use an IQuery to retrieve the same customer, the collections contain the correct number of items. However, when I look at the SQL that is generated in this case, I notice that NHibernate did not use a single query (with JOIN statements) to retrieve the customer entity. Instead, NHibernate used 3 separate queries (one for customer, one for the Item1's that belong to the Customer, and another one for the Item2's that belong to the Customer). So in fact, in this case, NHibernate ignored the fetch-strategy.
In attachment, you'll find an NUnit Testcase. I use SQL Server 2005, and the test-tables that I create, are created in the tempdb database. Note that you'll have to change the connection-string in the App.Config file.
Environment
None
Attachments
1
Activity
Show:
Fabio Maulo September 14, 2008 at 1:19 PM
Expected behavior. Multiple join fetch are not supported using <bag> since <bag> allow duplicated items. You must use <set> overriding Equals and GetHashCode according. doc 16.1.2
Fabio Maulo September 6, 2008 at 12:29 AM
multiple join-fetch are not allowed when a least one collection is a bag. If I well remember we have a specific exception in the trunk.
Situation:
I have a class 'Customer'. This class Customer has 2 collections: one collection for items of type 'Item1' and one collection for items of type 'Item2'.
I have mapped these 2 collections as 'bags' in my mapping file. These collections are not lazily loaded.
Suppose I have, in the DB a Customer object which has 3 records in the related Item1 table, and 2 records in the related Item2 table.
When I retrieve this customer using ISession.Get<Customer>(id), NHibernate returns me a Customer object which has 3 items for collection Item1 and 2 items for collection Item2, if the fetch-mode for these 2 collections is set to 'select'.
When I change the fetch-mode for these 2 collections to 'join' instead, and I retrieve the same Customer object (using ISession.Get<Customer>(id)), that Customer-object suddenly contains 6 items in collection Item1 and 6 items in the collection Item2.
The query that is generated by NHibernate however, looks ok and returns the correct results. It just seems to be that NHibernate creates to many objects (in fact, objects are being duplicated).
When I leave the fetch-mode set to 'join', and I use an IQuery to retrieve the same customer, the collections contain the correct number of items. However, when I look at the SQL that is generated in this case, I notice that NHibernate did not use a single query (with JOIN statements) to retrieve the customer entity. Instead, NHibernate used 3 separate queries (one for customer, one for the Item1's that belong to the Customer, and another one for the Item2's that belong to the Customer). So in fact, in this case, NHibernate ignored the fetch-strategy.
In attachment, you'll find an NUnit Testcase. I use SQL Server 2005, and the test-tables that I create, are created in the tempdb database. Note that you'll have to change the connection-string in the App.Config file.