Why does NHibernate delete and recreate all associations in a collection when I add one item to it?
Asked Answered
P

1

7

I'm doing some tests using NHibernate and I currently have two mapped entities, Orders and Products. As always an Order has a collection of Products, and I'm mapping this as:

<bag name="Products" cascade="all" lazy="true">
  <key column ="Order_ID" />
  <many-to-many class="Product" column="Product_ID" />
</bag>

And on the C# side:

public virtual IList<Product> Products
{
    get { return _Products; }
    set { _Products = value; }
}
private IList<Product> _Products = new List<Product>();

In the case I have one persisted Order (John's order) in the database with some items in its Products collection (an apple, an orange and a coconut) and I try to add a new item to the collection (a banana) I can see from the SQL output that NHibernate is doing something like this:

INSERT INTO Products_Table (Product_Name, Product_ID) VALUES ('Banana', @Banana_ID)
DELETE FROM Products WHERE Order_ID = @Johns_Order_ID
INSERT INTO Products (Order_ID, Product_ID) VALUES (@Johns_Order_ID, @Apple_ID)
INSERT INTO Products (Order_ID, Product_ID) VALUES (@Johns_Order_ID, @Orange_ID)
INSERT INTO Products (Order_ID, Product_ID) VALUES (@Johns_Order_ID, @Coconut_ID)
INSERT INTO Products (Order_ID, Product_ID) VALUES (@Johns_Order_ID, @Banana_ID)

Instead of simply doing something like this:

INSERT INTO Products_Table (Product_Name, Product_ID) VALUES ('Banana', @Banana_ID)
INSERT INTO Products (Order_ID, Product_ID) VALUES (@Johns_Order_ID, @Banana_ID)

So why does NHibernate delete all associations from the Products table to recreate them again when I'm only trying to insert a new product in it? How to avoid it?

Thanks in advance!

PS: I tried to use the inverse mapping attribute as suggested in this SO Question but even though the new product gets saved its association with an order doesn't.

EDIT:

Here is the code I'm using to modify the products list:

Order order = session.Load<Order>(orderId);
order.Products.Add(new Product() { Name = "Banana" });
using (ITransaction transaction = session.BeginTransaction())
{
    session.Update(order);
    transaction.Commit();
}
Pronucleus answered 8/6, 2012 at 19:52 Comment(2)
Can you show the code for modifying the product listLatishalatitude
Hi, I edited my question to include the code I'm using to modify the products list as you suggested.Pronucleus
H
5

There's already a similar question on SO: NHibernate Many-To-Many Is Deleting All Associations Before Inserting

From NHibernate's documentation:

Bags are the worst case. Since a bag permits duplicate element values and has no index column, no primary key may be defined. NHibernate has no way of distinguishing between duplicate rows. NHibernate resolves this problem by completely removing (in a single DELETE) and recreating the collection whenever it changes. This might be very inefficient.

Hayton answered 8/6, 2012 at 21:14 Comment(1)
Thanks for your answer, and I'm sorry for not being able to find that similar question myself. Now I switched my mapping to an idbag instead of a bag and everything is working like a charm!Pronucleus

© 2022 - 2024 — McMap. All rights reserved.