Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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();
}
like image 254
Thomas C. G. de Vilhena Avatar asked Jun 08 '12 19:06

Thomas C. G. de Vilhena


People also ask

How do I use NHibernate collections?

Just use NHibernate's collections the same way you use ordinary .NET collections, but make sure you understand the semantics of bidirectional associations (discussed later) before using them. Collection instances are distinguished in the database by a foreign key to the owning entity.

What are the disadvantages of using NHibernate?

Note: large NHibernate bags mapped with inverse="false" are inefficient and should be avoided. NHibernate can't create, delete or update rows individually, because there is no key that may be used to identify an individual row. 6.2.1. Collection foreign keys

Can NHibernate create or delete rows individually?

Note: large NHibernate bags mapped with inverse="false" are inefficient and should be avoided. NHibernate can't create, delete or update rows individually, because there is no key that may be used to identify an individual row.

What are the different types of mapping elements in NHibernate?

The NHibernate mapping element used for mapping a collection depends upon the type of interface. By example, a <set> element is used for mapping properties of type ISet . Apart from <set>, there is also <list> , <map> , <bag> , <array> and <primitive-array> mapping elements.


1 Answers

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.

like image 151
Miroslav Popovic Avatar answered Sep 28 '22 22:09

Miroslav Popovic