NHibernateの多対1の関係は親のみを削除します
-
03-07-2019 - |
質問
オブジェクト Product
と Supplier
の間に多対1の関係があります。 Supplier
に属する Product
を削除せずに Supplier
を削除できるようにする必要があります。
クラスの簡略版は次のとおりです。
public class Supplier {
public virtual IList<Product> Products { get; protected set; }
}
public class Product {
// Product belongs to a Category but Supplier is optional
public virtual Supplier Supplier { get; set; }
public virtual Category Category { get; set; }
}
FluentNHibernateを使用していますが、生成されるマッピングは次のとおりです。
<bag name="Products" cascade="save-update" inverse="true">
<key column="SupplierID" />
<one-to-many class="Me.Product, Me, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
<many-to-one name="Supplier" column="SupplierID" />
これにより、Productsテーブルに外部キーが作成されるため、サプライヤで直接削除しようとすると、外部キー制約エラーが発生します。リレーションシップのみが削除されることを期待して、カスケードを「すべて」に変更しようとしましたが、すべての製品と他の関連オブジェクトが削除されました。
この問題を解決する唯一の方法は、SupplierのProductsコレクションを反復処理し、Supplierプロパティをnullに設定することです。マッピングを通じてこの動作を実現する方法はありますか?
解決
マッピングプロパティは、エンティティが実際にロードされ、HQLを介してクエリを実行していない場合にのみ有効になります。例として、 Cascade = ALL
を指定した場合、クエリ&quot; delete from Supplier from id =:id&quot;
でサプライヤーを削除すると、おそらくhqlは(プログラム的な)カスケードをトリガーしないため、同じFK制約エラーが発生します。
製品は関係の所有側であると思われますが、これは良いことです。次の2つの選択肢があると思います。
- すべての製品を反復処理し、製品のサプライヤをnullに設定するメソッドをサプライヤでコーディングし、サプライヤを削除する前にこのメソッドを使用します
- サプライヤ削除を発行する前に、DAOが製品のサプライヤをnullに設定していることを確認してください
例:
public int Delete(Supplier s) {
return Session.CreateQuery("udpate Product set Supplier = null where Supplier = :supplier")
.SetParameter("supplier", s)
.ExecuteUpdate();
}
他のヒント
これをしないでください。
すべての製品にサプライヤーがあるというモデルの暗黙的または明示的な主張がある。この条件を強制するために外部キーがあります。製品を保持したままサプライヤを削除すると、モデルに違反し、おそらくこれが常に真であることに依存するコードの多くが失敗する可能性があります。
できることの1つは、すでに発見したことです。このサプライヤを持つすべての製品について、製品のサプライヤをnullに設定できます。これはあなたの条件に違反しませんが、「この製品の供給者が誰なのかわからない」と言うのと同じです。コードエラーが発生する可能性があります。
なぜこれを行うのですか?