3

EntityFrameworkとDbContextAPIを使用してアプリケーションをビルドしていますが、多対多の関係を持つオブジェクトの操作に問題があります。簡略化された保存方法は次のようになります

public void MyObj_Save(MyObj myobj)
{
  DbContext.Entry(myobj).State = EntityState.Added;
  DbContext.SaveChanges();
}

このコードは正常に機能しますが、MyObjに多対多の関係が含まれている場合、これは保存されません。古いPOCOAPIを使用して、関連するオブジェクトをコンテキストにアタッチする必要があることはわかっていますが、DbContextAPIを使用してこれを正しく行う方法を見つけることができません-以下の簡単な例

public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
  foreach (OtherObj otherObj in otherObjList)
  {
    DbContext.OtherObj.Attach(otherObj);
    myobj.OtherObj.Add(otherObj);
  }

  DbContext.Entry(myobj).State = EntityState.Added;
  DbContext.SaveChanges();
}

エラーは発生しませんが、リレーションは保存されません。何をすべきか?

4

2 に答える 2

3

あなたの(重要な!)コメントを引用します:

メソッドに送信するオブジェクトは添付され、EntityState は Unchanged です。私の DbContext の構成は、AutoDetectChangesEnabled を無効にしたことです...

したがって、コードは次のようになります。

DbContext.Configuration.AutoDetectChangesEnabled = false;

DbContext.Entry(myobj).State = EntityState.Unchanged;
foreach (OtherObj otherObj in otherObjList)
    DbContext.Entry(otherObj).State = EntityState.Unchanged;

// entering MyObj_Save method here
foreach (OtherObj otherObj in otherObjList)
{
    //DbContext.OtherObj.Attach(otherObj); // does not have an effect
    myobj.OtherObj.Add(otherObj);
}

DbContext.Entry(myobj).State = EntityState.Added;
DbContext.SaveChanges();

自動変更検出を無効にしているため、行内myobjの と のリストの関係が変更されたことに EF が気付かないため、これは実際には機能しません。したがって、エントリは結合テーブルに書き込まれません。保存されるのは自分だけです。OtherObjmyobj.OtherObj.Add(otherObj);myobj

ここで重要なのはエンティティの状態ではなく、関係の状態であるため、状態マネージャーを関係が保存されている状態にするために、エンティティに状態を設定することはできません。これらは、オブジェクト状態マネージャーの個別のエントリであり、変更検出によって作成および維持されます。

私は3つの解決策を見ます:

  • 設定DbContext.Configuration.AutoDetectChangesEnabled = true;

  • DetectChanges手動で呼び出す:

    //...
    DbContext.Entry(myobj).State = EntityState.Added;
    DbContext.ChangeTracker.DetectChanges();
    DbContext.SaveChanges();
    
  • myobj状態に設定する前に、コンテキストからnew を切り離しますAdded(これは私には非常にハッキリしています)。

    // entering MyObj_Save method here
    DbContext.Entry(myobj).State = EntityState.Detached;
    foreach (OtherObj otherObj in otherObjList)
    //...
    

ObjectContextオブジェクト状態マネージャーの関係エントリを手動で変更することは可能かもしれIObjectContextAdapterませんが、その方法はわかりません。

私の意見では、エンティティ (および関係) の状態を手動で操作するこの手順は、EF を操作する方法ではありません。AutoDetectChangesEnabledEF での作業をより簡単かつ安全にするために導入されました。これを無効にする唯一の推奨される状況は、高パフォーマンス要件 (たとえば、一括挿入) です。自動変更検出を必要なく無効にすると、このような検出が困難な問題が発生し、これらのバグを修正するには EF の内部動作に関する高度な知識が必要になります。

于 2012-05-29T11:54:47.937 に答える
2
public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList)
{
    DbContext.Entry(myobj).State = EntityState.Added;

    foreach (OtherObj otherObj in otherObjList)
    {
        (((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext)
            .ObjectContext)
            .ObjectStateManager
            .ChangeRelationshipState(myobj, otherObj,
                q => q.OtherObjs, EntityState.Added);
    }

    DbContext.SaveChanges();
}

繰り返しますが、これは単純化されたものであり、実際の例ではありません!

于 2012-05-29T16:55:36.020 に答える