NHibernate在删除之前更新了行?

时间:2011-01-21 21:09:40

标签: c# .net nhibernate

我对nhibernate有一种奇怪的行为。问题是 nhibernate在删除实体之前执行更新。 我有一个Category类和一个Product类。分类有一袋 产品。当我从Category中删除产品时,nhibernate就会这样做 以下:

  • 它更新我从集合中删除的产品实体
  • 从数据库中删除产品实体。

这是映射

  <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>

这是代码

    using (var session = NHibernateHelper.OpenSession()) 
    using (var transaction = session.BeginTransaction()) 
    { 
        var c1 = session.Load<Category>(32768); 
        c1.Ps.RemoveAt(0); 

        session.SaveOrUpdate(c1); 
        transaction.Commit(); 
    }

这是结果:

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

任何人都可以解释这种奇怪的行为吗?

感谢。

3 个答案:

答案 0 :(得分:12)

对类别上的产品包定义更改为true。将inverse设置为false告诉NHibernate Category对象是关系中键的所有者。

在Products集合上将inverse设置为false,NHibernate将Category视为关系的所有者。因此,当Products集合更改时,它会发出update语句以从Category中删除Product。然后删除是因为产品已被删除。

答案 1 :(得分:0)

编辑:对不起,对代码感到困惑; Ps不是一个非常具有描述性的属性。在这种情况下发生的是,由于您删除产品的方式(通过从类别中的集合中删除它然后保存类别),NHibernate首先从产品中删除对类别的引用,因为该产品没有更长属于类别(这是对象和表之间的关键转换;在OOP中,引用由包含对象保存,而在SQL中由包含对象保存)。现在记录不属于任何类别;它是孤儿,你告诉NHibernate清除其级联行为中的孤立引用,因此它会执行删除。

如果你只想用一个SQL语句来做,试试这个:

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
}

答案 2 :(得分:-2)

这种行为对我来说很正常。我对NHibernate没什么经验,但为了删除记录,我相信你通常会调用ISession.Delete方法,传入代表你要删除的记录的对象。

在您的情况下,您可以执行以下操作:

// delete a product
session.Delete(c1.Ps[0]);

或者,更清楚:

// find the product that I want to delete
var product = c1.Ps[0];

// now delete it
session.Delete(product);

您的代码似乎采用了一种删除产品记录的迂回方式。您的代码未明确删除产品,而是将产品记录与该类别记录取消关联。这就是NHibernate正在进行更新的原因。

请注意,在Category类中,您已将与Product类关系的“cascade”属性定义为:cascade="all-delete-orphan"。因为你的update语句导致产品记录被孤立,所以NHibernate可能会认识到应该根据你的级联设置删除产品记录,所以我认为这就是它决定执行delete语句的原因。