给出以下代码:
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);
}
TimeStamp数据存储在SQL Server 2012中定义为datetime2(0)的列中。
Assert失败,调试器证明两个Ticks值总是不同。
Expected: 636179928520000000 But was: 636179928523681935
未跟踪的值将始终四舍五入到最接近的秒(根据SQL存储的内容,这是预期的)。创建记录时,我保存的值来自DateTime.Now。
测试更多,对于我正在测试的每个对象,这似乎都不正确(不一致的刻度),仅适用于我最近插入的记录。查看代码并给出列定义的方式,对我来说这并不重要。
现在,为了让我的测试通过,我只是将DateTime值比较到第二个,这就是所需要的。但是,我只是想了解为什么会发生这种情况:为什么我不能可靠地比较两个DateTime值,具体取决于是否跟踪实体?
答案 0 :(得分:1)
我想出来了,所以回答我自己的问题;我发现我离开了这里的关键信息。我提到这个问题出现在测试中。我没有提到的是我们在单个事务中插入记录然后测试所有记录,并在单个DbContext中。
因为我对所有工作都使用相同的DbContext,所以缓存了为测试而插入的Alert对象。当我使用AsNoTracking查询对象时,DbContext必须刷新对象,然后再将它们发回给我(因为它们的当前状态没有被跟踪,因此EF不知道),显然没有更新缓存中的内容(因为我们告诉EF我们不想跟踪对象。)
在没有AsNoTracking的情况下查询相同的对象会导致缓存命中;那些插入的对象仍然在缓存中,因此返回缓存版本。
鉴于此,很明显为什么Ticks不匹配。非缓存对象从数据库中提取DateTime值,其中精度定义为仅将时间存储在最近的秒内。缓存的对象具有原始的DateTime.Now值,它将时间存储到ms。这就解释了为什么两个DateTimes之间的Ticks不匹配,即使两个对象代表相同的底层数据库记录。