The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发

1.乐观并发

EF Core 实现 乐观并发,假定并发冲突相对较少。 与 悲观 方法(即先锁定数据,然后才继续修改数据)不同,乐观并发不需要锁定,而是安排数据修改在保存时失败(如果数据自查询后已更改)。 此并发故障将报告给应用程序,应用程序可能会通过对新数据重试整个操作来相应地处理它。

在 EF Core 中,乐观并发是通过将属性配置为 并发令牌来实现的。 在查询实体时加载和跟踪并发令牌,就像任何其他属性一样。 然后,在 期间 SaveChanges()执行更新或删除操作时,数据库上的并发令牌值与 EF Core 读取的原始值进行比较。

代码触发乐观会如下错误:

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.

2.设置乐观锁

我的程序使用EF Core,然后给实体类设置了乐观并发 UseIdentityColumn

 public void Configure(EntityTypeBuilder<ChatRecord> builder)
{
//在 PostgreSQL 中,表名以及列名是不区分大小写的。这意味着在数据库中创建表时,无论您是使用大写、小写或混合大小写的名称,最终都会使用相同的名称来访问和操作该表。
//设置表
builder.ToTable("ChatRecord");
//设置表主键
builder.HasKey(e => e.ChatRecordId);
//设置主键自增
builder.Property(e => e.ChatRecordId)
.UseIdentityColumn();
}

3.什么情况下会触发乐观并发

乐观并发允许发生并发冲突,并在并发冲突发生时作出正确反应。 例如,Jane 访问院系编辑页面,将英语系的预算从 350,000.00 美元更改为 0.00 美元。

在 Jane 单击“保存”之前,John 访问了相同页面,并将开始日期字段从 2007/1/9 更改为 2013/1/9。

Jane 单击“保存”后看到更改生效,因为浏览器会显示预算金额为零的“索引”页面。

John 单击“编辑”页面上的“保存”,但页面的预算仍显示为 350,000.00 美元。 接下来的情况取决于并发冲突的处理方式:

  • 跟踪用户已修改的属性,并仅更新数据库中相应的列。

    在这种情况下,数据不会丢失。 两个用户更新了不同的属性。 下次有人浏览英语系时,将看到 Jane 和 John 两个人的更改。 这种更新方法可以减少导致数据丢失的冲突数。 这种方法具有一些缺点:

    • 无法避免数据丢失,如果对同一属性进行竞争性更改的话。
    • 通常不适用于 Web 应用。 它需要维持重要状态,以便跟踪所有提取值和新值。 维持大量状态可能影响应用性能。
    • 可能会增加应用复杂性(与实体上的并发检测相比)。
  • 让 John 的更改覆盖 Jane 的更改。

    下次有人浏览英语系时,将看到 2013/9/1 和提取的值 350,000.00 美元。 这种方法称为“客户端优先”或“最后一个优先”方案 。 客户端的所有值优先于数据存储的值。 基架代码不处理并发,“客户端优先”方案会自动执行。

  • 阻止在数据库中更新 John 的更改。 应用通常会:

    • 显示错误消息。
    • 显示数据的当前状态。
    • 允许用户重新应用更改。

    这称为“存储优先”方案。 数据存储值优先于客户端提交的值。 本教程中使用了“存储优先”方案。 此方法可确保用户在未收到警报时不会覆盖任何更改。

4.解决方案:重写SaveChanges

在 FrameworkDbContext 的DbContext类中重写SaveChanges方法

代码如下:

 public override int SaveChanges()
{
var saved = 0;
while (saved !=0) {
try {
base.SaveChanges();
saved++;
}
catch (DbUpdateConcurrencyException ex) {
foreach (var entry in ex.Entries) {
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues(); foreach (var property in proposedValues.Properties) {
var proposedValue = proposedValues[property];
var databaseValue = databaseValues[property];
} // Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);
}
}
} return saved;
}

代码可以在github中查找。我的开源项目修改的类的源码,源码地址:https://github.com/TerraMours/TerraMours_Gpt_Api/blob/main/TerraMours/TerraMours/Framework/Infrastructure/EFCore/FrameworkDbContext.cs

参考资料:https://learn.microsoft.com/zh-cn/ef/core/saving/concurrency?tabs=fluent-api

阅读如遇样式问题,请前往个人博客浏览: https://www.raokun.top

拥抱ChatGPT:https://first.terramours.site

开源项目地址:https://github.com/TerraMours/TerraMours_Gpt_Api

The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发的更多相关文章

  1. Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded

    asp.net  更新数据时报错:Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data ...

  2. 记录在EF Core级联更新时出现的错误The database operation was expected to affect 1 row(s), but actually affected 0 row(s) (低级错误导致)

    错误提示:The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data ma ...

  3. one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [3, 1280, 28, 28]], which is output 0 of LeakyReluBackward1, is at version 2;

    RuntimeError: one of the variables needed for gradient computation has been modified by an inplace o ...

  4. Cocos2d-x 3.0 编译出错 解决 error: expected &#39;;&#39; at end of member declaration

    近期把项目移植到cocos2d-x 3.0,在整Android编译环境的时候,出现一大堆的编译出错,都是类似"error: expected ';' at end of member dec ...

  5. Previous operation has not finished; run 'cleanup' if it was interrupted最简单有效的解决方法

    今天提交代码报错,看了看提示的错误,百度了一下,发现操作都比较繁琐,所以自己重新给一个最简单有效的. 有的要下载sqlite3.exe,借助它清空本地.svn\wc.db数据库文件里面的operati ...

  6. Json 文件 : 出现 Expected value at 1:0 问题的解决

    只要找一个json在线解析,验证你的json文件格式的正确性,错误可以忽略. 如要消除红叉,关闭Json Validation即可,如下操作:

  7. EntityFramework Core解决并发详解

    前言 对过年已经无感,不过还是有很多闲暇时间来学学东西,这一点是极好的,好了,本节我们来讲讲EntityFramewoek Core中的并发问题. 话题(EntityFramework Core并发) ...

  8. asp.net core 操作误区

    更新时提示数据变化错误 在更新事件中提示下面错误,在网上找了一下,大部分都是说是冲突问题,但是测试时同时只有一个客户端在进行操作,不应该会有冲突问题,后来发现编辑加载时的ID,和更新提交时的ID不同了 ...

  9. 【ASP.NET Core学习】Entity Framework Core

    这里介绍在ASP.NET Core中使用EF Core,这里数据库选的是Sql Server 如何使用Sql Server 添加模型 && 数据库迁移 查询数据 保存数据 如何使用Sq ...

  10. MySQL入门篇(七)之Xtrabackup备份与恢复

    一.Xtrabackup介绍 MySQL冷备.mysqldump.MySQL热拷贝都无法实现对数据库进行增量备份.在实际生产环境中增量备份是非常实用的,如果数据大于50G或100G,存储空间足够的情况 ...

随机推荐

  1. 2021-09-25:给定一个字符串数组,将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词指字母相同,但排列不同的字符串。示例 1:输入: strs = [“eat“, “tea“, “

    2021-09-25:给定一个字符串数组,将字母异位词组合在一起.可以按任意顺序返回结果列表.字母异位词指字母相同,但排列不同的字符串.示例 1:输入: strs = ["eat" ...

  2. Jenkins - 页面汉化

    Jenkins - 页面汉化 前言 对于不懂英文的人来讲,尤其是第一次使用Jenkins环境,看全英文的Jenkins页面是十分困难的: Jenkins对于不懂英文的用户有做汉化的插件包,但是汉化的不 ...

  3. c3p0的配置及简单应用

    首先简单了解一下JDBC和c3p0 Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸 ...

  4. T-SQL——批量刷新视图

    目录 0. 背景说明 1. 查询出所有使用了指定表的视图并生成刷新语句 2. 创建存储过程批量刷新 3. 刷新全部的视图 4. 参考 shanzm--2023年5月16日 0. 背景说明 为什么要刷新 ...

  5. vernemq 一个可用的入门指南之一:Mac下的安装及使用,使用MQTTX访问verneMQ

    因为百度到一篇简书的,不可用,所以写这么一篇,方便后来人 物联网的消息队列技术选型,很多地方会推荐使用VerneMQ,这里做一个安装实验记录,并非推荐. git clone https://githu ...

  6. Java并发(九)----线程join、interrupt

    1.join 方法详解 1.1 为什么需要 join? 下面的代码执行,打印 r 是什么? static int r = 0; public static void main(String[] arg ...

  7. Python 包安装和 postgresql 的一些问题

    今天安装 hgvs 这个 python 包的时候,遇到几个比较有代表性的问题,记录分享一下. hgvs is a Python package to parse, format, validate, ...

  8. 大家听过Java applet吗?为什么不再流行了

    前言 Java applet 不知道有同学听过吗?我也只是听过,并没有使用过.我特意去了解了一下它,本文就对 Java applet 进行简单介绍,说说它的辉煌与衰败.仅此而已,现在已经没人使用 Ja ...

  9. Python 九九乘法表的多种实现方式

    简介 九九乘法表是初学者学习编程的必要练手题目之一,因此各种语言都有对应的实现方式,而 Python 也不例外.在 Python 中,我们可以使用多种方式来生成一个简单的九九乘法表. 本文共介绍了七种 ...

  10. debug.exe的使用

    debug.exe的使用 debug.exe 是 Windows 操作系统自带的一个命令行调试工具,用于在 DOS 环境下进行汇编语言级别的调试操作.它可以让程序员以来自底层的方式逐步执行代码并检查每 ...