6

データ アクセス レイヤーとして EF4 を使用する ASP.Net MVC アプリケーションがあり、OptimisitcConcurrencyExceptions がスローされるはずのときにスローされないという予期しない動作が見られます。

問題を次のコードに単純化しました...

   using System.Linq;
    using Project.Model;

    namespace OptimisticConcurrency
    {
        class Program
        {
            static void Main()
            {
                Contact firstContact = null;
                using (var firstEntities = new ProjectEntities())
                {
                    firstContact = (from c in firstEntities.Contacts 
                       where c.LastName == "smith" select c).Single();
                }

                using (var secondEntities = new ProjectEntities())
                {
                    var secondContact = (from c in secondEntities.Contacts 
                       where c.LastName == "smith" select c).Single();

                    secondContact.Title = "a";
                    secondEntities.SaveChanges();
                }

                firstContact.Title = "b";

                using (var thirdEntities = new ProjectEntities())
                {
                    var thirdContact = (from c in thirdEntities.Contacts 
                       where c.LastName == "smith" select c).Single();

                    thirdContact.Title = firstContact.Title;

                    //EXPLICITLY SET VERSION HERE
                    thirdContact.Version = firstContact.Version;  

                    thirdEntities.SaveChanges();
                }
            }
        }
    }

これは、MVC アプリで発生することのかなり単純なバージョンですが、同じ問題が発生します。

thirdEntities で SaveChanges を呼び出すと、例外が発生し、何もスローされません。

さらに興味深いことに、SQL プロファイラーをアタッチすると、where 句で Version が使用されていることがわかりますが、使用されているのは firstEntities の値ではなく、firstEntities のバージョン値 (DB 内の現在の値) であり、明示的にすぐに設定されているにもかかわらずです。 SaveChanges が呼び出される前。SaveChanges は、設定された値ではなく、取得された値になるようにバージョンをリセットしています。

EDMX では、バージョンは、StoreGeneratedPattern が Computed に設定されるように設定されています。

ここで何が起こっているのか誰にも分かりますか?

4

1 に答える 1

10

これは問題です。列が に設定されるComputedと、アプリケーションでその値を設定することはできません (設定できますが、値は使用されません)。

編集:

データベースからエンティティをロードすると、デフォルトでコンテキストで追跡されます。コンテキストには、元の値が格納されます。元の値は、たとえばスナップショットの変更追跡に使用されますが、Computedプロパティの唯一の有効なソースとしても使用されます。エンティティにプロパティを設定Computedすると、値は使用されず、元の値が挿入されて使用されます。回避策は、元の値を変更することです (他のものを変更する前に):

using (var context = new TestEntities())
{
    var entityToUpdate = context.MyEntities.Single(e => e.Id == someId);
    entityToUpdate.Timestamp = entity.Timestamp;

    ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
    entry.ApplyOriginalValues(entityToUpdate);

    // set modified properties
    context.SaveChanges();
}

編集2:

ところで。実際にロードされたタイムスタンプと以前に取得されたタイムスタンプの両方を取得したら、データベースではなくアプリケーションで単純に比較できます。

于 2011-03-16T15:42:33.430 に答える