web-dev-qa-db-ja.com

NHibernateで子オブジェクトを削除する方法は?

子オブジェクトのIListと1対多の関係を持つ親オブジェクトがあります。子オブジェクトを削除する最良の方法は何ですか?親を削除していません。私の親オブジェクトには、子オブジェクトのIListが含まれています。 1対多の関係のマッピングは次のとおりです。

<bag name="Tiers" cascade="all">
  <key column="mismatch_id_no" />
  <one-to-many class="TGR_BL.PromoTier,TGR_BL"/>
</bag>

Clear()を使用してコレクションからすべてのオブジェクトを削除しようとした後、SaveOrUpdate()を呼び出すと、次の例外が発生します。

System.Data.SqlClient.SqlException: Cannot insert the value NULL into column

子オブジェクトを個別に削除してから親から削除しようとすると、例外が発生します。

deleted object would be re-saved by cascade

NHibernateで子オブジェクトを削除するのはこれが初めてです。何が間違っていますか?

編集:明確にするために-私は親オブジェクトを削除しようとはしていません、子オブジェクトだけを削除しようとしています。親には一対一の関係が設定されています。子オブジェクトのマッピングで多対1の関係を作成する必要もありますか?

78
Mark Struzinski

コレクションから項目を削除すると、NHibernateのデフォルトの操作モードは単純に関連付けを解除することになるため、最初のエラーが発生します。データベースでは、NHibernateは子行の外部キー列をnullに設定しようとします。その列ではNULLを許可しないため、SQL Serverはエラーを発生させます。コレクションをクリアしても必ずしも子オブジェクトが削除されるわけではありませんが、そのための1つの方法は、cascade = all-delete-Orphanを設定することです。これは、NHibernateに、外部キー列を設定する代わりに、新しく孤立した行を削除するよう通知します。

SaveOrUpdateを呼び出すと、NHibernateが最初にすべての子オブジェクトを削除するため、2番目のエラーが発生します。その後、どちらの関係も逆としてマークされないため、NHibernateは、子テーブルの外部キー列をnullに設定しようとします。行はすでに削除されているため、2番目のエラーが表示されます。これを修正するには、関係の片側でinverse = trueを設定する必要があります。これは通常、1つ(主キーまたは親)側で行われます。これを行わない場合、NHibernateは関係の各側に適切な更新を行います。残念ながら、2つの更新を実行するのは適切なことではありません。

リレーションシップの片側を常に逆側としてマークする必要があります。コーディング方法に応じて、カスケードを使用する必要がある場合としない場合があります。 Clear()を使用して1ショット削除を利用したい場合は、カスケードを定義する必要があります。

135
Chuck

Chuckの答えによれば、親側のマッピングにInverse = trueを追加することで問題を解決しました。

メッセージには多くのMessageSentToがあります。

[HasMany(typeof(MessageSentTo), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
public IList<MessageSentTo> MessageSendTos
{
    get { return m_MessageSendTo; }
    set { m_MessageSendTo = value; }
}

Castle ActiveRecordを使用しています。チャックありがとう。

3
hanuman0503

SaveOrUpdate()の代わりにmerge()を使用してみてください。また、カスケードがall-delete-Orphanに設定されており、親子関係が可逆的であることを確認してください(親でinverse = trueであり、not-null = trueのparent-idである子のフィールド) 。

2
Elie

この例では、製品をnullにできない多くの製品のカテゴリがあります。

フラッシュする前に製品を削除し、親のコレクションから削除することで問題を回避できますが、これに対するより良い解決策を探しています。

product = pRepo.GetByID(newProduct.ProductID);
product.Category.Products.Remove(product);
pRepo.Delete(product);

とにかくそれが役立つことを願って

2
Liath

カスケード属性値を「all」から「all-delete-Orphan」に変更します。

0
Thomas Tekavec