You need to enable JavaScript to run this app. 无并发场景下EF更新Transmit、Messages表随机报更新行数0异常
优惠活动
大模型
产品
解决方案
定价
更多

无并发场景下EF更新Transmit、Messages表随机报更新行数0异常

问题场景与故障现象

两张表为一对多关联关系,EDMX模型已正确识别关联,表结构如下:

(1)        (N)
Transmit -------------<  Messages
---------------          -----------
TransmitId (PK)          TransmitId (PK)
InternalId               SendingDate (PK)
LastStatus               Content
MessageType              Answer
                         Status

核心业务逻辑

代码运行在传入预先获取的transmitId的子过程中,实现对WebService调用结果的持久化,完整代码如下:

Try
    Using db As New MyDBEntities
        
        ' 调用WebService发送消息
        FullResp = api.MessagesPostWithHttpInfo(td)
        
        ' 更新Transmit表对应记录
        Dim t As Transmit = db.Transmit.Find(transmitId)
        t.InternalId = FullResp.Data.id
        t.LastStatus = If(FullResp.StatusCode = System.Net.HttpStatusCode.OK, Pionira.Status.Success, Pionira.Status.Failure)
        
        ' 更新关联的最新一条Messages记录
        With t.Message.OrderByDescending(Function(j) j.SendingDate).First() ' 取当前Transmit关联的最新Message
            .Answer = ApiClient.ReadAsBytes(ApiClient.Serialize(FullResp))
            .Status = t.LastStatus
        End With
        
        ' 提交数据库变更
        db.SaveChanges()
        
    End Using
    
Catch ex As Exception
    Return System.Net.HttpStatusCode.NotAcceptable
End Try

异常表现

该逻辑累计调用77次,约2/3概率抛出固定异常:

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

运行环境为本地电脑的本地数据库,无其他进程对目标表行进行并发修改,不存在并发访问场景。故障发生后,Messages表的部分数据如下(约定Status=2代表更新成功,Status=0代表更新失败):

TransmitId  SendingDate             Content Answer  Status
1084        2021-03-18 16:05:36.547 [BLOB]          0
1085        2021-03-18 16:05:37.583 [BLOB]          0
1086        2021-03-18 16:05:38.630 [BLOB]  [BLOB]  2
1087        2021-03-18 16:05:39.687 [BLOB]          0
1088        2021-03-18 16:05:40.787 [BLOB]          0
1089        2021-03-18 16:05:42.100 [BLOB]  [BLOB]  2

多次重试过程中,每次成功更新的行不固定,77次调用通常仅22-29条记录完成更新,从未出现全部更新成功的情况。

故障根本原因

该问题和并发场景无任何关联,核心触发原因是Messages表联合主键的字段类型精度映射不匹配,触发了EF内置的乐观并发校验逻辑:

  • EF会自动将所有主键字段纳入UPDATE语句的WHERE匹配条件,即使未显式配置并发令牌,只要实体主键值和数据库实际存储值存在偏差,就会判定为更新异常。
  • 从样本数据的时间戳格式判断,SendingDate对应的数据库字段大概率是SQL Server原生datetime类型,该类型的实际存储精度为3.33毫秒,并非严格意义上的毫秒精度;而.NET端DateTime类型精度为100纳秒,EF从数据库读取时间值映射为.NET实体时,会按照自身精度规则补全时间的小数位。
  • 执行UPDATE时,EF会使用实体上存储的、带补全精度的SendingDate值做WHERE匹配,但数据库实际存储的原始时间值因精度截断,和.NET实体上的值并不完全相等,最终导致UPDATE语句匹配到0行,抛出“影响行数异常”的并发类报错。
  • 故障呈随机分布的原因:不同时间戳与3.33毫秒精度网格的对齐关系是随机的——部分时间戳读取后的值回写时刚好能匹配数据库原值,就能更新成功;其余存在精度偏差的就会匹配失败。这完全匹配观察到的约1/3成功率、成功行随机分布的现象。

内容的提问来源于stack exchange,提问作者Skippy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 12:36:02