2015-09-22 87 views
7

Entity Framework 6.0.0を使用して、トランザクションを閉じるときに例外が発生しています。トランザクションをロールバックする際の例外 - 接続はすでに閉じられていますか?

私はテーブルの並行変更に問題があったので、トランザクションでラップしましたが、今はロールバック時に例外が発生しています。

コード:

public LockInfo getSharedLock(string jobid) 
{ 
    using (var myDbContext = new MyDbContext()) 
    { 
     using (var transaction = myDbContext.Database.BeginTransaction()) 
     { 
      try 
      { 
       this.logger.log("Attempting to get shared lock for {0}", jobid); 

       var mylocks = 
        myDbContext.joblocks.Where(j => j.customerid == this.userContext.customerid) 
         .Where(j => j.jobid == jobid) 
         .Where(j => j.operatorid == this.userContext.operatorid); 

       var exclusiveLock = mylocks.FirstOrDefault(
        j => j.lockstatus == LockInfo.LockState.Exclusive); 
       if (exclusiveLock != null) 
       { 
        this.logger.log("{0} already had exclusive lock, ignoring", jobid); 
        return LockInfo.populate(exclusiveLock); 
       } 

       var sharedLock = mylocks.FirstOrDefault(
        j => j.lockstatus == LockInfo.LockState.Shared); 
       if (sharedLock != null) 
       { 
        this.logger.log("{0} already had shared lock, ignoring", jobid)); 
        sharedLock.lockdt = DateTime.Now; 
        myDbContext.SaveChanges(); 

        return LockInfo.populate(sharedLock); 
       } 

       var joblock = new joblock 
       { 
        customerid = this.userContext.customerid, 
        operatorid = this.userContext.operatorid, 
        jobid = jobid, 
        lockstatus = LockInfo.LockState.Shared, 
        sharedLock.lockdt = DateTime.Now 
       }; 

       myDbContext.joblocks.Add(joblock); 
       myDbContext.SaveChanges(); 
       transaction.Commit(); 

       this.logger.log("Obtained shared lock for {0}", jobid); 
       return LockInfo.populate(joblock); 
      } 
      catch (Exception ex) 
      { 
       transaction.Rollback(); 
       this.logger.logException(ex, "Exception in getSharedLock(\"{0}\")", jobid); 
       throw; 
      } 
     } 
    } 
} 

あなたは上記のコードでは、ログを見ることができます。私たちはデータベースでもログを有効にしています。ログトレース:

=================== 
NORMAL TicketLockController.getLock("AK2015818002WL") 
=================== 
SQL Opened connection at 9/22/2015 2:47:49 PM -05:00 
=================== 
SQL Started transaction at 9/22/2015 2:47:49 PM -05:00 
=================== 
NORMAL Attempting to get shared lock for AK2015818002WL 
=================== 
SQL SELECT TOP (1) [Extent1].[customerid] AS [customerid] 
    ,[Extent1].[jobid] AS [jobid] 
    ,[Extent1].[lockdtdate] AS [lockdtdate] 
    ,[Extent1].[lockdttime] AS [lockdttime] 
    ,[Extent1].[operatorid] AS [operatorid] 
    ,[Extent1].[lockstatus] AS [lockstatus] 
    ,[Extent1].[changes] AS [changes] 
FROM [dbo].[joblock] AS [Extent1] 
WHERE ([Extent1].[customerid] = 'TESTTK') 
    AND ([Extent1].[jobid] = 'AK2015818002WL') 
    AND ([Extent1].[operatorid] = 'ADMIN') 
    AND (N'Exclusive' = [Extent1].[lockstatus]) 
=================== 
SQL SELECT TOP (1) [Extent1].[customerid] AS [customerid] 
    ,[Extent1].[jobid] AS [jobid] 
    ,[Extent1].[lockdtdate] AS [lockdtdate] 
    ,[Extent1].[lockdttime] AS [lockdttime] 
    ,[Extent1].[operatorid] AS [operatorid] 
    ,[Extent1].[lockstatus] AS [lockstatus] 
    ,[Extent1].[changes] AS [changes] 
FROM [dbo].[joblock] AS [Extent1] 
WHERE ([Extent1].[customerid] = 'TESTTK') 
    AND ([Extent1].[jobid] = 'AK2015818002WL') 
    AND ([Extent1].[operatorid] = 'ADMIN') 
    AND (N'Shared' = [Extent1].[lockstatus]) 
=================== 
SQL INSERT [dbo].[joblock] (
    [customerid] 
    ,[jobid] 
    ,[lockdtdate] 
    ,[lockdttime] 
    ,[operatorid] 
    ,[lockstatus] 
    ,[changes] 
    ) 
VALUES (
    @0 
    ,@1 
    ,@2 
    ,@3 
    ,@4 
    ,@5 
    ,NULL 
    ) 
=================== 
SQL Closed connection at 9/22/2015 2:47:50 PM -05:00 
=================== 
EXCEPTION Unhandled exception caught: The underlying provider failed on Rollback. 
=================== 
EXCEPTION Inner Exception: Value cannot be null. 
Parameter name: connection 

2つの選択が成功していて、何らかの理由で挿入が失敗しています。例外をスローし、何らかの理由でロールバック()が実行される前に接続が終了しています。

私が間違っていることは何ですか?内部例外のため

at System.Data.Entity.Core.EntityClient.EntityTransaction.Rollback() 
    at korterra.kt_api.Shared.TicketLockWrangler.getSharedLock(String jobid) 
    at korterra.kt_ws.ApiControllers.Shared.TicketLockController.getSharedLock(TicketLockDTO ticketLockDTO) 
    at lambda_method(Closure , Object , Object[]) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) 
    at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18`1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Tracing.ITraceWriterExtensions.<TraceBeginEndAsyncCore>d__18`1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext() 

スタックトレース:スタックトレース====外側例外の

スタックトレース追加

====

at System.Data.Entity.Utilities.Check.NotNull[T](T value, String parameterName) 
    at System.Data.Entity.Infrastructure.Interception.DbTransactionInterceptionContext.WithConnection(DbConnection connection) 
    at System.Data.Entity.Infrastructure.Interception.DbTransactionDispatcher.Rollback(DbTransaction transaction, DbInterceptionContext interceptionContext) 
    at System.Data.Entity.Core.EntityClient.EntityTransaction.Rollback() 
+0

ToStringの完全な例外を投稿してください。エラーログが不十分です。 – usr

+0

また、多くの場合、トランザクションをコミットしていません。それは本当に意図的ですか? – usr

+0

私はオンデマンドでこれを再現することはできません。 QA環境で断続的に表示されるものです。私はdevでそれを見たことがない。私が既に投稿したもの以外の唯一の情報はスタックトレースです。これは単純に例外がコードの中で発生したことを示しています。 –

答えて

6

議論の後、Iロールバックを試みる前に例外のログ記録を開始し、エラーを明らかにしました。

トランザクションがデッドロックされました:

Exception in getSharedLock("ticketnumber123456"): An error occurred while updating the entries. See the inner exception for details. 

Inner Exception: An error occurred while updating the entries. See the inner exception for details. 

Inner Exception: Transaction (Process ID 139) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 

あなたは、トランザクションがデッドロックの対象に行われた言ったとき、私は、読んでいるところでは、それはすでにロールバックされています。おそらく、なぜ我々は例外を取得しているのですか?

デッドロックが発生したときに認識し、ロールバックしない、トランザクションを使用しない、プライマリキー違反が発生したときに再試行する方法が考えられます。

+0

このコードではRollbackを呼び出さないでください。また、これはEFバグです。それはクラッシュすべきではありません。クリーンな例外を使用してAPIの使用エラーなどを報告する必要があります。あなたはこれについてEFレポでGitHubの問題を開くことができますか? – usr

+0

私は現在トランザクションを使用しようとしていませんが、基礎となるレコードが変更されたときに単純に再試行します - 楽観的なロック。 –

関連する問題