我们正在使用EF Core6,目前看到PROD中的一个API偶尔会抛出DbUpdateConcurrencyException.到目前为止,我们还没有实现逻辑(并发判断/RowVersion)来管理乐观并发.我想在调试时重现相同的错误,所以我遵循了以下步骤

  1. 已加载项目列表
  2. 已手动更新数据库(SQL Server)上的列
  3. 从代码调用SaveChanges()

令人惊讶的是,这在调试时没有引发任何错误.我想知道为什么这些并发更新会在Prod中导致异常,而不是在调试时?

推荐答案

如果表没有设置并发令牌,则不会收到更新并发错误(即过时数据),但会收到与删除相关的删除并发错误.以下是报告"数据库操作预期影响1行(S),但实际影响0行(S)"的错误

您可以通过编辑现有实体来重现此过程,然后在数据库中删除该实体,然后呼叫SaveChanges.收到此错误可能会令人困惑,因为当您没有您认为会删除行的代码时,可能会发生此错误.

如果您的系统确实删除了有多个活动会话正在进行的行,则需要处理此问题.如果您在不应该删除行的时候收到此消息,则可能导致此类问题的一个常见错误是设置集合导航属性.

例如,假设一个博客实体有一个与之相关联的标签列表,并且您有一个屏幕来添加或删除博客上的相关标签.代码如下:

var blog = _context.Blogs
    .Include(x => x.Tags)
    .Single(x => x.BlogId == blogId);

blog.Tags = updatedTags;

...是很糟糕的.Setter将用于单个导航属性,但绝不应用于集合.在集合中单独添加和删除相关标签,因为EF的更改跟踪器绑定到在阅读博客条目时设置的标签集合.

其他要判断的罪魁祸首是可能遗漏了警告的无意编辑,这些警告可能已经污染了DbContext.

例如,您可能有一行代码在某处执行判断,如下所示:

if (blog.Status = Statuses.Draft)

不是:

if (blog.Status == Statuses.Draft)

编译器将在第一条语句中生成一条关于潜在意外赋值的警告,但如果您的解决方案已经有几十个您习惯于忽略的编译器警告,那么在您不打算更新博客的地方可能会错过这个警告,当保存一些不相关的东西时,它会try 更新博客或其他您不期望的实体,导致您徒劳无功.帮助避免这种情况的有用步骤:

  • 清除项目中的所有编译器警告.这样,当这样的事情发生时,你就有更好的机会发现它.
  • 对于只读操作,在查询中使用AsNoTracking()或Projection( Select 匿名类型或DTO/ViewModel),而不是读取跟踪的实体.对于要解决的意外赋值,您仍然会有一个"错误",但它不会 destruct DbContext.

使用调试器跟踪这些受污染的实体之一可能有点棘手,但如果您碰巧用可重现的示例中断了异常,请查看更改跟踪器以判断DbContext正在try 更新哪些实体.你可能会发现一个你没想到会看到的实体.至于生产,您可能会有一个分析器捕获数据库上的SQL语句,然后遍历所有内容,执行更新,并找到导致没有更新的行的内容.

Csharp相关问答推荐

自定义JsonEditor,用于将SON序列化为抽象类

在WPF.NET 6中使用C++/WinRT组件(但实际上是任何WinRT组件)

一小时后,自定义缓存停止在App Insight中保存

TDLib与机器人共享电话号码

使用C#中的SDK在Microsoft Graph API上使用SubscribedSkus的问题

使用HttpResponseMessage中的嵌套列表初始化JSON

如何使用EF Core和.NET 8来upsert到具有多对多关系的表?

为什么AggregateException的Catch块不足以处理取消?

在DoubleClick上交换DataGridViewImageColumn的图像和工具提示

当使用Dapper映射DBNull时,我可以抛出异常吗?

HelperText属性不支持复杂内容(混合C#和标记)

RabbitMQ群集的MassTransit配置问题

将操作从编辑页重定向到带参数的索引页

如何使用Npgsql从SELECT获得所有查询结果

我的命名管道在第一次连接后工作正常,但后来我得到了System.ObjectDisposedException:无法访问关闭的管道

Maui:更改代码中的绑定字符串不会更新UI,除非重新生成字符串(MVVM)

如何从SignalR获取连接客户端的域

无效的Zip文件-Zip存档

使用免费的DotNet库从Azure函数向Azure文件共享上的现有Excel文件追加行

无法对包含字符串的列进行排序.请与实体框架联接