0

[MainEntity] と仮定する 1 つのエンティティがあります。このメイン エンティティには、以下のような子エンティティがあります。

MainEntity:
          -> ChildEntity1
          -> ChildEntity2
          -> ChildEntity3
          -> ChildEntity4
          -> ChildEntity5

すべての子エンティティは、メイン エンティティと 1 対多の関係にあります。

メイン エンティティと最初の 3 つの子エンティティの UI ユーザー更新データ。UI では、ChildEntity1、ChildEntity2、ChildEntity3 は GridView、ListBox、および CheckListBox で表されます。ユーザーは、これらのコントロールを介して子レコードを追加/更新できます。以下に示すように、データを挿入/更新するサンプル コード:

BL class:
========
public class EntityManager
 {
      public EntityManager ()
      {
            MainEntityData = new MainEntity();
      }
      public MainEntity MainEntityData= { get; set; }

      public void InsertUpdate()
      {
            DAL.InsertMainEntityData(MainEntityData);

      }
}


UI Codes:
=========

EntityManager objEntityManager = new EntityManager();

if (lnkInsertUpdate.CommandArgument == "Update")
   objEntityManager.MainEntity.ID =                        
                         int.Parse(Request.QueryString["ID"].ToString());

objEntityManager.MainEntity.Name = txtName.Text;
objEntityManager.MainEntity.Description = txtDescription.Text;
-----------------------------------------
-----------------------------------

ChildEntity1 objChildEntity1 = null;
foreach (ListItem item in lstSelectedProduct.Items)
{
  objChildEntity1 = new ChildEntity();
  objChildEntity1.ClientProductID = int.Parse(item.Value);
  objChildEntity1.IsActive = true;
  objChildEntity1.CreatedBy = "Admin";
  objChildEntity1.CreatedDate = DateTime.Now;
  objEntityManager.MainEntity.ChildEntitys1.Add(objChildEntity1);
}

-----------------------------------
codes for childentity2,childentity3
--------------------------------
objEntityManager.InsertUpdate()


DALCodes:
=========
public static void InsertMainEntityData(MainEntity objMainEntity)
{
    using (TransactionScope ts = new TransactionScope())
    {
      try
      {
        using (DBEntities context = DatabaseFactory.GetContext())
        {
        if (objMainEntity.ID > 0)
        {
         MainEntity mainEntityToUpdate = 
 context.MainEntitys.Include("ChildEntity1").Include("ChildEntity2").Include("ChildEntity3").First(o => o.ID == objMainEntity.ID);

          mainEntityToUpdate = objMainEntity;
          context.MainEntitys.Attach(mainEntityToUpdate);
         context.ObjectStateManager.ChangeObjectState(mainEntityToUpdate, 
                       EntityState.Modified);
        }
       else
        {
                context.AddToMainEntitys(objMainEntity);
                context.SaveChanges();
                 ts.Complete();
           }
          catch (Exception ex)
          {
            ts.Dispose();
          }
           finally
           {
        }
}

新しいレコードの挿入は正常に機能していますが、更新中に次のエラーが発生しました:

同じキーを持つオブジェクトが ObjectStateManager に既に存在します。ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません。

この問題を解決する方法を教えてください??

ありがとう、

ポール

4

1 に答える 1

1

次の行でロードさmainEntityToUpdateれたものをデタッチされたもので上書きしているため、このエラーが発生します。objMainEntity

mainEntityToUpdate = objMainEntity;

次に、このオブジェクトをアタッチします。

context.MainEntitys.Attach(mainEntityToUpdate);

はまだコンテキストにアタッチされているためmainEntityToUpdate(ロード後)、同じキーがコンテキストにアタッチされている2つのオブジェクトがあり、これは禁止されており、例外が発生します。

代わりに次を使用して、エンティティのスカラー プロパティを更新できます。

MainEntity mainEntityToUpdate = context.MainEntitys
    .First(o => o.ID == objMainEntity.ID);

context.MainEntitys.ApplyCurrentValues(objMainEntity);

ただし、子コレクションではなく、スカラー プロパティのみを更新します。状態を に設定してModifiedも子コレクションは更新されないためです。

すべての子コレクションを含むメイン エンティティを更新することは、実際にはそれほど簡単ではありません。データベースからすべての子コレクションを含む元のエンティティをロードし (メイン エンティティのロード開始Include("ChildX")は正しい)、それを切り離さobjMainEntityれたコレクションおよび更新されたコレクションと比較する必要があります。「比較」とは、ユーザーによって追加されたコレクション項目、削除されたコレクション項目、まだそこにある (ただし、プロパティ値が変更されている可能性がある) 項目を検出し、それに応じて元のコレクションに項目を追加または削除する必要があることを意味します。変更検出はこれらの変更に従い、 を呼び出すと適切な SQL ステートメントをデータベースに書き込みますSaveChanges

これを行う方法のスケッチ ( DbContext/EF >= 4.1 の場合) はこちら: https://stackoverflow.com/a/5540956/270591

于 2012-05-29T16:12:00.147 に答える