c# - Entity Framework 核心: Unable to catch SqlException

标签 c# asp.net-core entity-framework-core asp.net-core-signalr

我试图在将行插入数据库表时实现一些乐观锁定。

我想做的是从数据库中获取一行。如果具有给定键的行不存在,则首先插入该行。我目前正在测试高并发场景。

这个想法是:如果该行已被另一个线程添加,则捕获异常并从数据库重新读取实体。但是,我似乎无法捕获异常。

这是有问题的方法

    private async Task<Counter> AcquireCounterAsync(string resType)
    {
        var repo = _dbContext.Set<Counter>();

        while (true)
        {
            var ctr = await repo.FindAsync(resType);

            if (ctr != null)
                return ctr;

            ctr = new Counter(resType);

            try
            {
                Console.WriteLine("Trying to add " + resType);
                repo.Add(ctr);
                await _dbContext.SaveChangesAsync();
                Console.WriteLine("Created " + resType);
                return ctr;
            }
            catch (SqlException ex)
            {
                // this block is never entered
                Console.WriteLine("SqlException was thrown: " + ex.Message);
                continue;
            }
        }            
    }

这是我的日志,异常(exception)是德语,但这只是违反主键约束的预期:

Trying to add test/test0
Trying to add test/test0
Created test/test0
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (157ms) [Parameters=[@p0='?' (Size = 128), @p1='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SET NOCOUNT ON;
      INSERT INTO [counters] ([ResourceType], [Value])
      VALUES (@p0, @p1);
System.Data.SqlClient.SqlException (0x80131904): Verletzung der PRIMARY KEY-Einschränkung 'PK_counters'. Ein doppelter Schlüssel kann in das dbo.counters-Objekt nicht eingefügt werden. Der doppelte Schlüsselwert ist (test/test0).
Die Anweisung wurde beendet.
   at System.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__122_0(Task`1 result)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues, CancellationToken cancellationToken)
ClientConnectionId:d1f14d55-c95b-4c19-b1bc-468241df225d
Error Number:2627,State:1,Class:14

有问题的类被瞬时注入(inject)信号中心。我觉得我可能做了一些根本性错误的事情,但我还看不出来。

编辑:我也尝试使这个方法同步,结果相同,只是堆栈跟踪稍微长一些,直到 SignalR 中心的调用。所以肯定不会被捕获。

我的修复:澄清一下:我通过捕获“DbUpdateException”并使所有方法同步来修复此问题。如果我使用异步方法,我仍然无法捕获“DbUpdateException”甚至“Exception”。所以这只是与这个问题部分相关:Cannot catch SqlException in Entity Framework

最佳答案

我已经设置了一个像这样的小型演示

    var uid = Guid.NewGuid();
    using (var context = new DemoContext())
    {
       context.Stuff.Add(new Stuff { Uid = uid, Data = "stuff1" });
       await context.SaveChangesAsync();
    }
    using (var context = new DemoContext())
    {
       context.Stuff.Add(new Stuff { Uid = uid, Data = "stuff2" });
       await context.SaveChangesAsync();
    }

它包装在 try ... catch block 中,我可以捕获抛出的异常,但它的类型为 Microsoft.EntityFrameworkCore.DbUpdateException ,并带有 >System.Data.SqlClient.SqlException 就像你的包裹在里面一样。

你是否在其他地方捕获并仅重新抛出内部异常?尝试在代码中捕获Exception,只是为了确保。

关于c# - Entity Framework 核心: Unable to catch SqlException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52015151/

相关文章:

asp.net-core - project.json : what are they? 中的框架和导入部分

c# - ASP.NET core 2.2 web api 记录与数据保护 key 相关的警告 : how should we handle this issue?

sql-server - 多个 Include/ThenInclude 在 EF Core 中导致重复

C# 标准 : rationale for "Do not provide public event member variables"?

c# - ComVisible .NET 程序集和 app.config

c# - .NET 工具 : Extract Interface and Implement Wrapper Class

c# - 在这种情况下,EF Core 生成的 SQL 效率很低,有什么解决方法吗?

c# - 在联接中使用委托(delegate) CompiledQuery?

c# - 在 ASP.NET Core 中通过 DI 从初始化对象初始化对象

c# - 在 ASP.NET 5 中使用自定义 UserStore 和 RoleStore