10

Webサービスへの呼び出しでは、次のコードを使用して、呼び出し元が有効なセッションを持っていることを確認します。有効なセッションが見つかった場合、セッションの詳細が更新され、変更が保存されます。すべてが十分に単純で、正常に機能します。

// Create the Entity Framework context
using(MyContext ctx = CreateMyContext())
{
     // Get the user session for the client session         
     UserSession session = (from us in context.UserSessions.Include("UserEntity")
                            where us.SessionId = callerSessionId
                            select us).FirstOrDefault<UserSession>();

     if (session == null)
         return false;
     else
     {
         // Update session details
         session.Calls++;
         session.LastAccessed = DateTime.Now.Ticks;
         Console.WriteLine("Call by User:{0}", session.UserEntity.Name);

         // Save session changes back to the server
         ctx.SaveChanges();
         return true;
     }    
}

同じ呼び出し元、つまり同じセッションが複数の同時呼び出しを行うまで、すべてが正常に機能します(これは完全に有効です)。この場合、デッドロックが発生することがあります。SQL Server Profilerを使用すると、次のことが発生していることがわかります。

発信者Aは選択を実行し、ユーザーセッションの共有ロックを取得します。発信者Bは選択を実行し、同じユーザーセッションで共有ロックを取得します。発信者Bの共有ロックが原因で、発信者Aは更新を実行できません。発信者Aの共有ロックが原因で、発信者Bは更新を実行できません。デッドロック。

これは単純で古典的なデッドロックシナリオのようであり、それを解決するための簡単な方法が必要です。確かに、ほとんどすべての実際のアプリケーションでこれと同じ問題が発生しますが、デッドロックについて言及しているEntityFrameworksの本はありません。

4

3 に答える 3

15

これについて話している記事をここで見つけまし。基本的に、EF呼び出しを取り巻くトランザクションを開始および停止できるように聞こえます...ブロックは次のコード例を示しているため、クレジットはDiego B Vegaに送られます...ブログ投稿は、追加情報を含む別のブログにもリンクしています。

using (var scope = new TransactionScope(TransactionScopeOption.Required, new 
    TransactionOptions { IsolationLevel= IsolationLevel.Snapshot }))
{
    // do something with EF here
    scope.Complete();
}
于 2012-10-27T04:34:28.957 に答える
1

以下はあなたのために働きますか?

using(MyContext ctx = CreateMyContext())
{

     ctx.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");


     // Get the user session for the client session         
     ...
}
于 2013-08-15T23:56:23.620 に答える
0

おそらくトランザクションを使用して各セッションがありますか?この場合、トランザクションが保存しようとすると、両方のトランザクションが共有ロックから排他ロックにアップグレードしようとするため、デッドロックが発生します。EFは楽観的同時実行性を優先するため、これは十分に文書化されていないようです。

これを回避する1つの方法は、次のようなものを使用してupdatelockヒントを提供することです。

return context.TestEntities
          .SqlQuery("SELECT TOP 1 Id, Value FROM TestEntities WITH (UPDLOCK)")
          .Single();
}

参照:エンティティフレームワーク6と悲観的な並行性

于 2019-07-20T13:11:56.060 に答える