6

Entity Framework 4.3.1 から (偶然にも、.NET 4 に対して Visual Studio 2010 でビルドされた ASP .NET MVC 3 Web アプリケーションから) この例外が発生しています。

System.InvalidOperationException: データベースへの変更は正常にコミットされましたが、オブジェクト コンテキストの更新中にエラーが発生しました。ObjectContext が矛盾した状態にある可能性があります。内部例外メッセージ: オブジェクトをオブジェクト コンテキストに追加できません。オブジェクトの EntityKey には、オブジェクトが既に別の関係に参加していることを示す ObjectStateEntry があります。

私はいくつかのグーグルを行い、これにたどり着きました(msdnで):

保存時の InvalidOperationException

その中で、Jeff Derstadt(受け入れられた回答)は次のように述べています。

次に SaveChanges を呼び出すと、コンテキストは変更を保持し、状態エントリの修正を試みます。これを行うと、一時的な EntityKey を完全な EntityKey に変換する「キーの修正」が実行されます。この場合、一時キー TKP2 は P2 のキーと等しくなります。コンテキストは、状態マネージャーのキー エントリを完全なエンティティ エントリに「昇格」させようとし、その過程でグラフを修正します。P1.Spouse = P2 であるため、P2.Spouse は P1 である必要がありますが、追加された項目があったため、P2.Spouse は既に P3 に等しく、EntityReference は複数の値を持つことはできません。

私はここで少し「汚い」方法で考えているので、私の質問はこれです...

保存変更後のオブジェクト グラフがどのように見えるかはあまり気にしないため (つまり、要求が終了したため、とにかく破棄されます)、データが挿入されました (SQL Server でそれを見ると、実際には完全に問題ありません)。デバッガーで続行した後) - Entity Framework にこの手順を実行しないように指示する方法はありますか (したがって、この例外を取得せず、おそらく少し時間も節約できます)?

4

2 に答える 2

1

これを行う公式の方法はありませんが、これを試してください:

private static readonly Lazy<MethodInfo> internalDeleteMethod = new Lazy<MethodInfo>(
    () => typeof(ObjectContext).Assembly.GetType("System.Data.Objects.EntityEntry").GetMethod("Delete", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(bool) }, null)); 


public static void Delete<TEntity>(Func<DbContext> dbContextFactory, TEntity entity,
    Func<DbContext, IEnumerable<DbEntityValidationResult>> onSaving = null,
    Action<DbContext> onSaved = null,
    bool referenceFixup = true)
        where TEntity : class
{
    Guard.ArgumentNotNull(dbContextFactory, "dbContextFactory");
    Guard.ArgumentNotNull(entity, "entity");
    onSaving = onSaving ?? (_ => null);
    onSaved = onSaved ?? (_ => { });

    using (var dbContext = dbContextFactory())
    {
        var set = dbContext.Set<TEntity>();
        set.Attach(entity);

        var entry = ((IObjectContextAdapter)dbContext).ObjectContext.ObjectStateManager.GetObjectStateEntry(entity);
        internalDeleteMethod.Value.Invoke(entry, new object[] { referenceFixup });

        dbContext.SaveChanges();
     }
 }
于 2013-10-16T09:19:32.290 に答える
1

より良いヘルプが必要な場合は、少しのコードを投稿する必要があります。

それでも、私はこれらのエラーのいくつかと格闘していることに気付き、基本的な真実にたどり着きました。データベースに既に存在するものを参照している場合は、それを参照してください。キーやコードだけを使用するのではなく、DbContext で表される実際のオブジェクトを使用してください。DbContext.Entry() メソッドを使用して、これらを見つけることができます。

一方、元のオブジェクトと参照されるオブジェクトの両方が実行時に作成される場合は、それらに一意の ID が与えられ、その ID が (データベースではなく) エンティティ フレームワークによって実行時に認識されるようにしてください。それ以外の場合 (たとえば、NEWID() Sql 関数に依存している場合)、オブジェクト A がオブジェクト B を参照している場合、同じオブジェクトが一度データベースに格納されたときに取得した ID とは異なるランタイム ID を使用している可能性があります。

私が言うように、少しのコードを投稿していただければ、より良い助けになるかもしれません;)

于 2012-12-10T11:01:11.147 に答える