You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF6与SQL Server 2016 DateTime字段并发检查问题求助

解决EF Code First在SQL Server 2016下datetime并发令牌的异常问题

我之前也踩过这个坑!SQL Server 2016在datetime类型的精度处理上和2012有细微差异,这几乎肯定是导致你并发检查失败的根源。下面是我整理的几个排查和解决步骤:

1. 先确认EF生成的参数类型是否匹配

EF有时候会“自作主张”把.NET的DateTime参数映射为datetime2类型,哪怕你已经用Fluent API指定了列类型是datetime。这种情况下,数据库里存储的是经过舍入的datetime值,但EF用高精度的datetime2参数去对比,自然会不匹配导致并发冲突。

验证方法:打开EF的日志功能,查看更新操作生成的SQL语句:

// 在你的DbContext构造函数里添加日志输出
public YourDbContext()
{
    this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}

运行更新操作后,看日志里的WHERE子句参数,如果是@p0 datetime2而不是@p0 datetime,那就是这个问题。

解决办法:在Fluent API里显式指定参数的DbType,或者全局配置所有DateTime属性的列类型和参数类型:

// 全局配置(针对EF6)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    // 强制所有DateTime属性使用datetime类型
    modelBuilder.Properties<DateTime>()
        .Configure(c => 
            c.HasColumnType("datetime")
             .HasDbType(System.Data.DbType.DateTime));
    
    // 单独配置你的LastModificationTime(如果全局配置不够的话)
    modelBuilder.Entity<YourEntity>()
        .Property(e => e.LastModificationTime)
        .HasColumnName("MODIFQUAND")
        .HasColumnType("datetime")
        .HasDbType(System.Data.DbType.DateTime)
        .IsConcurrencyToken();
}

2. 手动截断DateTime到SQL datetime的精度

SQL Server的datetime类型精度只有3.33毫秒(每个刻度是3333333 ticks),而.NET的DateTime精度是100纳秒。直接赋值DateTime.Now的话,存储到数据库时会被舍入,但EF在并发检查时会用原始的高精度值去对比,导致不匹配。

解决办法:写一个扩展方法,把DateTime截断到符合SQL datetime的精度:

public static class DateTimeExtensions
{
    public static DateTime ToSqlDateTimePrecision(this DateTime dateTime)
    {
        // SQL datetime的每个刻度是3333333 ticks
        var roundedTicks = (long)Math.Round(dateTime.Ticks / 3333333.0) * 3333333;
        return new DateTime(roundedTicks, dateTime.Kind);
    }
}

然后在更新实体的时候,用这个方法赋值:

entity.LastModificationTime = DateTime.Now.ToSqlDateTimePrecision();

3. 检查数据库兼容级别(临时排查用)

SQL Server 2016默认兼容级别是130,而2012是110。虽然不推荐长期使用,但可以临时把兼容级别降到110,看看是否解决问题,以此确认是不是兼容级别带来的差异:

ALTER DATABASE YourDatabase SET COMPATIBILITY_LEVEL = 110;

如果这样能解决,说明你需要针对130级别调整代码(还是建议用前面的方法,而不是一直降低兼容级别)。

4. 升级EF版本

如果你用的是比较老的EF版本(比如EF6.0以前),可能存在对SQL Server 2016的兼容性bug。尝试升级到EF6的最新稳定版本,很多这类问题都已经被修复了。

最后验证

修改后,再通过EF日志查看生成的SQL,确保WHERE子句里的LastModificationTime参数是datetime类型,并且赋值的时间已经被截断到正确精度,这样并发检查就能正常工作了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:11:43