2011-01-21 9 views
7

私はnhibernateで奇妙な動作をしています。問題は、 nhibernateがエンティティを削除する前に更新を実行することです。 私はCategoryクラスとProductクラスを持っています。カテゴリには の袋があります。私はカテゴリーから製品を削除すると、NHibernateのは には、以下のん: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 

誰でもこの奇妙な振る舞いを説明できますか?

ありがとうございました。

答えて

12

カテゴリの商品バッグの定義にtrueを反転させてください。 inverseをfalseに設定すると、NHibernateはCategoryオブジェクトが関係上のキーの所有者であることを知らせます。

NHibernateは、Productsコレクションでinverseをfalseに設定すると、カテゴリを関係の所有者とみなします。したがって、Productsコレクションが変更された場合、更新ステートメントが発行されてカテゴリから製品が削除されます。その後、製品が削除されたため削除が行われます。

+0

ありがとう、あなたの記事は非常に有用だった:) – Davita

0

編集:申し訳ありませんが、コードで混乱しました。 Psはあまり説明的ではありません。この場合、何か起こっているのは、製品を削除する方法(カテゴリのコレクションから削除してカテゴリを保存する)のために、NHibernateは最初に製品からCategoryへの参照を削除します。より長いカテゴリに属しています(これはオブジェクトとテーブルの間の主要な変換です; OOPでは参照は包含オブジェクトによって保持され、SQLでは包含オブジェクトによって保持されます)。レコードはどのカテゴリにも属しません。それは孤立しており、カスケード動作で孤立した参照をクリーンアップするようにNHibernateに指示したので、削除を実行します。

あなただけの1つの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 
} 
+0

こんにちはkeith、返信いただきありがとうございます。あなたが正しいですが、このistuationでは、私はカテゴリを削除していない、私はちょうどカテゴリから製品を削除しています。だから、この操作は参照を分離する必要はありませんし、私の状況では、これはまったく必要ではありません。 – Davita

-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は更新を行っています。

カテゴリクラスで、Productクラスとの関係の「カスケード」属性を次のように定義していることに注意してください。cascade="all-delete-orphan"。あなたの更新ステートメントがそのProductレコードを孤立させるため、NHibernateはカスケード設定に従ってProductレコードを削除する必要があると認識しているので、deleteステートメントを実行することが前提です。

関連する問題