34

私はEntity Framework 4を使用しており、「Cascade Delete」を設定した親子関係があります。したがって、親から子を削除すると、SaveChanges() を呼び出すと子が削除されることが期待されます。

        cuRepository.Attach(_controlUnit);
        foreach (var recipe in recipes) {
            _controlUnit.Recipes.Remove(recipe);
            //repository.DeleteObject(recipe);
        }

代わりにエラーが発生します:

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

子を明示的に削除すると (コメント行を参照)、すべて問題ありません。私は何が欠けていますか?

4

5 に答える 5

30

remove ステートメントでオブジェクトを削除していません。代わりに、レコードを変更して孤立させようとしています (外部キーを null に設定することにより)。データベースにはその列に非 null 制約があり、そうすることができません。

于 2010-03-31T16:37:40.197 に答える
27

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspxは、あなたに何が起こったのかを正確に説明しています。


次のようなクラス設計があると仮定します。

サンプルクラスの設計

Entity Frameworkは、必要な外部キー列を生成し、NOT NULLそれらに制約を追加します。これは、すべてのレシピが常に1つのControlUnitに関連付けられるためです。

したがって、実行時に、次のレイアウトのようなオブジェクトが作成されます。

実行時のオブジェクト図

これでコードが機能し、RecipeオブジェクトとそのControlUnitの間の関係が削除されました。

関係が削除されたオブジェクト

NOT NULLこの時点で保存しようとしていますが、データベースには外部キー列に入れるためのControlUnitIDがありません。現在のオブジェクトの状態は上記のクラス図に違反しており、すべてのレシピが1つのControlUnitに関連付けられていることを前提として生成されたデータベースレイアウトに保存することはできません。これが、データベースが変更の保存を拒否し、例外が表示される理由です。

これは、エンティティを削除する行のコメントを解除したときに機能する理由も説明しています。エンティティはその関係とともにデータベースから削除されるため、制約に違反することはなく、例外もありません。

「しかし、私ON DELETE CASCADEは関係を設定しました...」

はい。ただし、関係の削除ではなく、オブジェクトの削除時にのみトリガーされます。ON DELETE CASCADEセットを使用すると、これは機能するはずです。

controlUnitRepository.DeleteObject(_controlUnit);
// deletes the ControlUnit and all associated Recipe entities

ControlUnitとの関係の削除時にレシピエンティティの削除をトリガーする場合、関係は単純な関連付けではなく、構成である必要があります。

構成を含む更新されたクラス図

EFはこれをネイティブにサポートしていませんが、関係の識別を使用して動作をエミュレートできます。エンティティが親エンティティとの識別関係にあり、その関係が削除されると、エンティティも削除されます。これは最初からあなたの意図だったようです。関係の識別の詳細については、EF4との識別関係の実装を参照してください。ここでは、EF4との識別関係を実装し、より多くの資料にリンクしています。

于 2010-09-14T15:17:03.733 に答える
11

context.DeleteObject(recipe)ループ内に追加

于 2010-03-31T16:39:30.197 に答える
8

子と親の関係を識別関係にする場合は、コレクションから子エンティティを削除できます。子のキーを、親のプライマリ ID キーを含む複合キーにする必要があります。そうすれば、EF は子を削除する必要があることを認識します。

識別関係は、基本的に、親が存在しない場合、子は意味がないと言います。これは、リレーションシップが削除されたときに子を削除しても安全であることを EF が認識していることを意味します。

この質問を参照してください。リレーションシップを識別して子エンティティを挿入すると、「テーブルの ID 列に明示的な値を挿入できません」という問題が発生し、これはコレクションから子を削除して SaveChanges の問題を解決することは可能ですか?

于 2012-06-20T00:08:39.190 に答える
3

エンティティを削除するためだけにDALにメソッドを追加しないために、この拡張機能を使用します( http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-から取得したコード) to-get-the-objectcontext-from-an-entity.aspx):

public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships
{
    RelationshipManager relationshipManager = entityToDelete.RelationshipManager;

    IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();
    if (relatedEnd == null)
    {
        throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship.");
    }

    var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
    if (query == null)
    {
        throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext.");
    }

    query.Context.DeleteObject(entityToDelete);
    collection.Remove(entityToDelete);
}

そこで、のようなエンティティを削除しますOrder.Products.Delete(prod)

拡張機能を使用するための制約は次のとおりです
。-エンティティには関係が必要です。
-エンティティはObjectContextにアタッチする必要があります。

于 2012-06-11T12:12:59.673 に答える