EF Core如何配置并发令牌 EF Core IsConcurrencyToken方法

来源:这里教程网 时间:2026-02-21 17:33:45 作者:

EF Core 配置并发令牌的核心目标是启用乐观并发控制,防止“丢失更新”——即多个用户同时读取同一行、各自修改后保存,后保存者无意中覆盖前者的更改。关键不在于“加锁”,而是在

SaveChanges()
时自动比对原始值,不一致就抛出
DbUpdateConcurrencyException
,由你决定如何响应。

两种主流配置方式:数据注解 vs Fluent API

你可以任选其一,推荐 Fluent API(更集中、可测试、不污染实体类);但

1771665883
注解因数据库原生支持,仍是首选。

1771665883
(最推荐)
:适用于 SQL Server 等支持
rowversion
的数据库。EF Core 会自动映射为
byte[]
类型列,每次更新行时数据库自动生成新值,无需手动维护。
public class Product {<br>
  public int Id { get; set; }<br>
  public string Name { get; set; }<br>
  1771665883<br>
  public byte[] RowVersion { get; set; }<br>
}
[ConcurrencyCheck]
:标记任意属性(如
LastModified
Status
),适合业务语义明确的字段。但需确保该字段在每次更新时被正确赋值(比如手动设置
DateTime.UtcNow
),否则检测失效。
用 Fluent API 的
IsConcurrencyToken()
:灵活度最高,可配置普通字段或导航属性,也支持链式调用。例如:
modelBuilder.Entity<Order>()<br>
  .Property(o => o.Version)<br>
  .IsConcurrencyToken();

注意:若字段本身不是数据库自增/自动更新类型(如
int
DateTime
),你必须在业务逻辑中主动更新它的值,否则并发检测形同虚设。

IsConcurrencyToken() 和 IsRowVersion() 的区别

IsConcurrencyToken()
是通用方法,把任意属性设为并发检查点,但值要靠代码维护;
IsRowVersion()
是专用于
rowversion
/
timestamp
列的快捷方式,仅 SQL Server 支持,数据库自动管理值,更可靠。

.IsRowVersion()
时,EF Core 迁移会生成带
rowVersion: true
的列定义,且该列不可写入(只读);
.IsConcurrencyToken()
配置
DateTime
字段,则迁移只是普通列,你得确保每次
SaveChanges()
前都设置了新时间戳。

配置后必须处理异常,否则并发冲突直接崩掉

配置完令牌只是第一步。真正起作用的是捕获

DbUpdateConcurrencyException
并做合理应对,常见策略有:

重载最新数据,提示用户“他人已修改”,让用户选择是否覆盖; 自动合并:保留数据库中的部分字段(如审核状态),应用用户修改的字段(如备注); 乐观重试:用
entry.OriginalValues.SetValues(databaseValues)
同步到最新快照,再调用
SaveChanges()
重试(适合幂等操作)。

验证是否生效的小技巧

写个简单测试:查出一条记录 → 手动用 SQL 修改数据库里对应的

RowVersion
或并发字段 → 再调用
SaveChanges()
。如果抛出
DbUpdateConcurrencyException
,说明配置成功。

基本上就这些。不复杂但容易忽略的是:配了令牌却没处理异常,或者用了

IsConcurrencyToken()
却忘了更新字段值——这两点会让乐观锁完全失效。

相关推荐