sql-server - 为什么 AsNoTracking 会影响 DateTime 精度?

标签 sql-server entity-framework-6

鉴于以下代码:

var dbRecords = _context.Alerts.AsNoTracking()
                        .Where(a => a.OrganizationId == _authorization.OrganizationId)
                        .ToList();
var dbRecords2 = _context.Alerts
                         .Where(a => a.OrganizationId == _authorization.OrganizationId)
                         .ToList();

foreach (var untrackedRecord in dbRecords) {
    var trackedRecord = dbRecords2.First(a => a.Id == untrackedRecord.Id);

    Assert.AreEqual(untrackedRecord.TimeStamp.Ticks, trackedRecord.TimeStamp.Ticks);
}

其中时间戳数据存储在 SQL Server 2012 中定义为 datetime2(0) 的列中。

Assert 失败,并且调试器表明两个 Ticks 值总是不同的。
Expected: 636179928520000000 But was:  636179928523681935

未跟踪的值将始终四舍五入到最接近的秒数(这是预期的,基于 SQL 存储的内容)。创建记录时,我保存的值来自 DateTime.Now。

再测试一些,对于我正在测试的每个对象,这似乎不是真的(不一致的滴答声),仅适用于我最近插入的记录。查看代码并考虑到列的定义方式,我不清楚为什么这很重要。

现在,为了让我的测试通过,我只是将 DateTime 值与秒进行比较,这就是所需要的。但是,我只是想了解为什么会发生这种情况:为什么我不能根据实体是否被跟踪来可靠地比较两个 DateTime 值?

最佳答案

我想通了,所以回答我自己的问题;我发现我忽略了这里的关键信息。我提到这个问题是在测试中出现的。我没有提到的是,我们正在插入记录,然后在单个事务和单个 DbContext 中测试所有记录。

因为我对所有工作都使用相同的 DbContext,所以为测试而插入的 Alert 对象会被缓存。当我使用 AsNoTracking 查询对象时,DbContext 必须在将对象返回给我之前刷新对象(因为它们的当前状态没有被跟踪,因此 EF 不知道),显然没有更新缓存中的内容(因为我们告诉 EF 我们不想跟踪对象)。

在没有 AsNoTracking 的情况下查询相同的对象会导致缓存命中;那些被插入的对象仍然在缓存中,所以缓存的版本被返回。

鉴于此,很明显为什么 Ticks 不匹配。非缓存对象从数据库中提取 DateTime 值,其中定义的精度仅存储最接近秒的时间。缓存的对象具有原始 DateTime.Now 值,它将时间存储到毫秒。这解释了为什么 Ticks 在两个 DateTimes 之间不匹配,即使两个对象表示相同的基础数据库记录。

关于sql-server - 为什么 AsNoTracking 会影响 DateTime 精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41285747/

相关文章:

entity-framework - Entity Framework 6 是否有计划的发布日期?

linq - 错误地创建了一个应用联接

c# - 我可以克隆一个 IQueryable 以在另一个 DbContext 的 DbSet 上运行吗?

sql-server - 如何查找包含 A-Z0-9 之外字符的字段

sql - 我可以在 sql server 2008 profiler 中监控特定表的性能吗

c# - 多对多导航属性为空

c# - 如何强制触发 OnModelCreating 每个 DataContext 初始化

android.database.sqlite.SQLiteException : no such column : id (code 1) while compiling : s

sql - 根据结果​​对列进行分组

SQL Server批量插入