22

外部キー関係でEntity Framework Code Firstを使用しています。アプリケーションでエンティティ ICollection からオブジェクトを削除する方法を調査しています。

子関係を持つエンティティがある場合、Add メソッドを使用してオブジェクトを ICollection に直接追加できます。remove を使用すると、エラーが発生します

System.InvalidOperationException が発生しました Message=The operation failed: 1 つ以上の外部キー プロパティが null 非許容であるため、リレーションシップを変更できませんでした。リレーションシップに変更が加えられると、関連する外部キー プロパティが null 値に設定されます。外部キーが null 値をサポートしていない場合は、新しい関係を定義するか、外部キー プロパティに別の非 null 値を割り当てるか、関連のないオブジェクトを削除する必要があります。

これは、コレクションの削除が外部キーを無効にすることによってのみ関係を削除するためであることを理解しています。エンティティにビジネス ロジックを記述し、削除できるようにしたいと考えていました。

そのため、リポジトリからルート エンティティを取得します。たとえば、OrderRepository から注文し、エンティティの特定のメソッドを呼び出します。たとえば、Order.AddOrderline(Orderline orderline)これにより OrderLine が Orders に追加されます。virtual ICollection<OrderLine> OrderLines

Order.CancelOrderline(int orderLineId)ただし、単純に ICollection から削除すると、貯蓄の変更でエラーが発生するため、次のようなコードを書くことはできません。

オブジェクトコレクションを操作するだけでこれを達成する方法はないようです。明らかに、コンテキストから直接削除できます。しかし、私はそれをエンティティの一部にしたいと思います。Entity Framework の SaveChanges イベントで、外部キーのない特定のエンティティをクリーンアップできますか? 外部キーが null の場合にどのエンティティを削除できるかを EF に伝える必要があることは明らかです。

現在、リポジトリ パターンを使用しているため、コントローラーはコンテキストにアクセスできません。明らかに、OrderLine リポジトリーまたは Order リポジトリーの remove OrderLine メソッドを使用できます。ただし、永続化メカニズムを参照せずにエンティティにコードを記述できるかどうかは疑問です。

考え?私たちはこれについてすべて間違っていますか?他の ORM では、子コレクションから削除できますか?

4

2 に答える 2

40

以下が解決策かどうかはわかりませんが、 EntityFrameworkは関係の識別をサポートしています。このような関係では、親(プリンシパル)に対する子エンティティ(依存)の外部キーは、子エンティティの(複合)プライマリキーの一部である必要があります。たとえば、DbContextデータアノテーションを使用する場合、モデルクラスは次のようになります。

public class Order
{
    [Key]
    public int OrderId { get; set; }

    public ICollection<OrderLine> OrderLines { get; set; }
}

public class OrderLine
{
    [Key, ForeignKey("Order"), Column(Order = 1)]
    public int OrderId { get; set; }

    [Key, Column(Order = 2)]
    public int OrderLineId { get; set; }

    public Order Order { get; set; }
}

OrderLineId必要に応じて、自動生成されたIDを作成できます。重要なのは、FKtoOrderがPKの一部であるということだけです。

たとえば、このようなコード...

using (var ctx = new MyContext())
{
    var order = ctx.Orders.Include("OrderLines").Single(o => o.OrderId == 1);
    var orderLineToDelete = order.OrderLines
        .FirstOrDefault(ol => ol.OrderLineId == 5);
    if (orderLineToDelete != null)
        order.OrderLines.Remove(orderLineToDelete);

    ctx.SaveChanges();
}

...実際にデータベースからを削除orderLineToDeleteます。

詳細については、「関係の識別と非識別に関する考慮事項」のセクションを参照してください

于 2012-06-14T13:21:14.637 に答える
2

ご覧のとおり、コレクションからエンティティを削除しただけでは、エンティティがオブジェクト コンテキストに関連付けられてハングアップし、呼び出し時にエラーが発生しますSaveChanges()。私はドメイン イベントを使用して、リポジトリを介してオブジェクト コンテキストからエンティティを削除する整然とした方法を有効にしました。

この質問への回答で、このアプローチについて詳しく説明しました。

于 2012-06-14T13:09:33.667 に答える