配置Timestamp乐观并发后有时无法捕获DbUpdateConcurrencyException的原因
问题原因分析
你遇到的偶发无法捕获DbUpdateConcurrencyException的问题,本质是触发乐观并发检测的前提条件没有满足,EF Core基于Timestamp字段的乐观并发逻辑如下:
- 查询实体时,EF会将当前数据库中该记录的
RowVersion值存入变更跟踪器 - 执行
SaveChanges时,生成的UPDATE语句会自动拼接WHERE 主键 = 待更新ID AND RowVersion = 初始查询到的值的条件 - 只有该UPDATE语句影响行数为0时,EF才会抛出
DbUpdateConcurrencyException
偶发不触发异常的常见原因按概率从高到低排列:
- 操作时序错误:部分测试场景中你先在SSMS执行了UPDATE修改数据,之后程序才运行到
var a = context.Students.FirstOrDefault(x => x.Id == 1);这行查询代码。此时查询拿到的RowVersion已经是SSMS修改后的最新值,SaveChanges时WHERE条件可以正常匹配到记录,更新成功不会抛出异常。 - 调试过程意外刷新了实体的跟踪值:断点暂停期间,如果你在Visual Studio的即时窗口、监视窗口执行了该Student实体的查询操作,或者触发了相关的跟踪查询,会导致变更跟踪器里存储的
RowVersion被覆盖为数据库最新值,SaveChanges时不会检测到并发冲突。 - SSMS的更新操作未生效:测试过程中可能出现PriKey=1的记录被删除、执行SQL时选错了数据库、SQL执行报错等情况,导致
VerCol字段没有被更新,EF的UPDATE语句可以正常匹配到记录,自然不会抛出异常。 - 表字段配置错误(小概率):如果你的Student表是手动创建而非EF Code First自动生成的,可能出现
VerCol字段不是rowversion/timestamp类型的问题,普通binary字段修改数据时不会自动更新,自然触发不了并发检测。你可以执行SQLSELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Student' AND COLUMN_NAME = 'VerCol'确认字段类型。
内容的提问来源于stack exchange,提问作者narojay
相关产品推荐
相关产品推荐

