1

この質問の前に、次のように説明します。インターネット上には、古い「同じキーを持つオブジェクトが既に ObjectStateManager に存在する」という問題に関する投稿が 100 万件あることを知っています。私のシナリオはもう少し複雑だと思います。

DbContext を作成し、呼び出されたリポジトリに渡す UnitOfWork クラスがあります。私が使用しているパターンは、ASP.NET サイトの Unit of Work チュートリアルに厳密に従っています。チュートリアルとは異なり、私のリポジトリはビジネス エンティティを取り込み、それらをデータ エンティティにマップし、CRUD アクションを実行します。マイ ビジネス ロジックは、ビジネス エンティティでのみ機能します。サンプルの Business Manager クラスで私がやろうとしていることは次のとおりです。

_unitOfWork.Repository.Add(entity);
_unitOfWork.Save(); // context.SaveChanges() under the hood

...Perform some operations on the model...

_unitOfWork.Repository.Update(entity);
_unitOfWork.Save();

以下は、リポジトリの Update メソッドのサンプルです。

public virtual void Update(entity)
{
  var dataEntity = // map from business entity to data;

  _context.Entry(dataEntity).State = EntityState.Modified;
}

最後の行で明らかに失敗します。ここで私の混乱が始まります:

  • エンティティの状態は切り離されています
  • State を Modified または Unchanged に変更しようとすると、上記の ObjectStateManager 例外が発生します。
  • コンテキストからエンティティをデタッチしようとすると (((IObjectContextAdapter)_context).ObjectContext.Detach(entity);) エンティティがコンテキストにアタッチされていないという例外が発生するため、エンティティをデタッチできません。非常に紛らわしいです(確かに、私が見逃している基本的なものです)。
  • 他の多くの投稿では、データベース呼び出しを行い、リポジトリ内のそのエンティティを更新してから、_unitOfWork.Save() を提案しています。私はこのアプローチが好きではありません。エンティティを更新するために不要なネットワーク呼び出しを行う必要はありません。

リポジトリの Update メソッドは、2 つのシナリオを処理する必要があります。1) 現在コンテキストによって追跡されていないエンティティの更新、および 2) 現在コンテキストによって追跡されているエンティティの更新。2番目の部分は私が苦労しているものです。

どんな助けや洞察も大歓迎です。

ありがとう!

4

2 に答える 2

1

これは、 new と同じキーを持つオブジェクトがコンテキストにアタッチされていることを意味しますdataEntity。既存のオブジェクトと新しいエンティティはどちらもデータベース内の同じエントリを表していますが、2 つの異なるオブジェクトです。

これは、の寿命が_context長すぎることを示している可能性がありますが、コードから判断するのは困難です。ただし、コンテキストが以前にデータベースからエンティティを取得するために使用され、その後 によって複製されたことは確かですvar dataEntity = ...

コンテキストの寿命を短くする必要があるかもしれませんが、わかりません。問題ないと思われる場合は、Localコレクションを使用して、エンティティが既に存在するかどうかを確認することをお勧めします。これにより、データベースのラウンドトリップが節約されますFind

于 2013-03-13T07:51:38.200 に答える
0

私はうまくいくように見えるハイブリッドソリューションを見つけました:

public virtual void Update(TB entity)
        {
            var dataEntity = Mapper.Map<TB, TD>(entity);

            var pkey = _dbSet.Create().GetType().GetProperty("Id").GetValue(dataEntity);
            var entry = _context.Entry(dataEntity);

            if (entry.State == EntityState.Detached)
            {
                var attachedEntity = _dbSet.Find(pkey);

                if (attachedEntity != null)
                {
                    var attachedEntry = _context.Entry(attachedEntity);
                    attachedEntry.CurrentValues.SetValues(dataEntity);
                }
                else
                {
                    entry.State = EntityState.Modified;
                }
            }
            else
            {
                entry.State = EntityState.Modified;
            }
        }
于 2013-03-12T18:36:14.840 に答える