NHibernate updates row before deleting it?
I'm having a strange behavior with nhibernate. The problem is that nhibernate performs an update before it deletes an entity. I have a Category class and a Product class. Category has a bag of products. When I remove a product from Category, nhibernate does the following:
- It updates the product entity which I removed from collection
- It deletes the product entity from database.
Here's mapping
<class name="Category">
<id name="Id">
<generator class="hilo" />
</id>
<property name="Name" lazy="false" length="20" />
<bag name="Products" cascade="all-delete-orphan" lazy="false"
inverse="false">
<key column="CategoryId" />
<one-to-many class="Product" />
</bag>
</class>
<class name="Product">
<id name="Id">
<generator class="hilo" />
</id>
<property name="Name" lazy="false" />
<property name="Discontinued" lazy="false" />
<property name="Price" lazy="false" />
<many-to-one name="Category"
class="Category"
column="CategoryId"
cascade="none" />
</class>
Here's the code
using (var session = NHibernateHelper.OpenSession())
using (var transaction = session.BeginTransaction())
{
var c1 = session.Load<Category>(32768);
开发者_如何学C c1.Ps.RemoveAt(0);
session.SaveOrUpdate(c1);
transaction.Commit();
}
and here's the result:
exec sp_executesql N'UPDATE Product SET CategoryId = null WHERE
CategoryId = @p0 AND Id = @p1',N'@p0 int,@p1 int',@p0=32768,@p1=65537
go
exec sp_executesql N'DELETE FROM Product WHERE Id = @p0',N'@p0
int',@p0=65537
go
Anyone can explain this strange behavior?
Thanks.
Change inverse to true on your definition for your Products bag on Category. Setting inverse to false tells NHibernate that the Category objects is the owner of the key on the relationship.
With inverse set to false on the Products collection, NHibernate sees the Category as an owner of the relationship. So when the Products collection changes it issues the update statement to remove the Product from the Category. Then the delete occurs because the Product was deleted.
EDIT: Sorry, got confused by the code; Ps
is not a very descriptive property. What's happening in this case is that, because of the way you are deleting the Product (by removing it from the collection on Category and then saving the Category), NHibernate is first removing the reference to the Category from the Product, because that Product no longer belongs to the Category (this is a key translation between objects and tables; in OOP the reference is held by the containing object, while in SQL it's held by the contained object). Now the record doesn't belong to any Category; it's orphaned, and you've told NHibernate to clean up orphaned references in its cascade behavior, so it performs the delete.
If you want to do it with just one SQL statement, try this:
using (var session = NHibernateHelper.OpenSession())
using (var transaction = session.BeginTransaction())
{
var c1 = session.Load<Category>(32768);
var toDelete = c1.Ps[0];
c1.Ps.RemoveAt(0);
session.Delete(toDelete);
transaction.Commit();
//you shouldn't need to update the c1 object
}
This behavior looks normal to me. I have little experience with NHibernate, but in order to delete a record I believe you typically call the ISession.Delete
method, passing in the object that represents the record you want to delete.
In your case, you might be able to do the following:
// delete a product
session.Delete(c1.Ps[0]);
Or, to be more clear:
// find the product that I want to delete
var product = c1.Ps[0];
// now delete it
session.Delete(product);
Your code appears to be taking a roundabout way of deleting the Product record. Your code is not explicitly deleting the product, rather it is disassociating that Product record with that Category record. That's why NHibernate is doing the update.
Notice that in your Category class you've defined the "cascade" attribute of the relationship to the Product class as the following: cascade="all-delete-orphan"
. Because your update statement causes that Product record to be orphaned, NHibernate probably recognizes that the Product record should be deleted, according to your cascade setting, and so I assume that's why it decides to execute the delete statement.
精彩评论