2013-03-21 61 views
2

我有一个视图ObjectDisplay,它由两个相关的表格组成:ObjectStateState代表Object的状态,并且该视图从最近的State中为每个Object提取一些细节。视图是否立即反映其基础表中的数据更改?

在显示此信息的页面上,用户可以输入一些注释,它会创建一个新的State。在创建新的State后,我立即从ObjectDisplay中取出Object,然后将其发回并放入局部视图中,并替换页面上的网格中的Object

// Add new State. 
db.States.Add(new State() 
{ 
    ObjectId = objectId, 
    Comments = comments, 
    UserName = username 
}); 

// Save the changes (executes all of the above). 
db.SaveChanges(); 

// Return the new Object information. 
return db.Objects.Single(c => c.ObjectId == objectId); 

根据我的分贝跟踪,该Single呼叫发生SaveChanges呼叫后约70毫秒,它发生在同一个SPID。

现在是问题:数据库默认RecordDate的值在StateGETUTCDATE() - 我自己没有提供日期。我看到的是Object返回的旧StateStateRecordDate和旧的State的新State信息的Comments我看到返回的Object有旧的State的信息。当我刷新页面时,所有正确的信息都在那里,但是在数据库/ EF的初始调用中返回了错误的信息。

那么..什么可能是错的?该视图能否更新得足够快? EF可能会发生什么?我真的不知道从哪里开始寻找。

+0

什么隔离级别的查询与运行?是否在不同的会话上调用视图来更改数据? – Oded 2013-03-21 21:01:58

+0

@Oded:从跟踪中,'Audit Login'行有'set transaction isolation level read committed'。两者都在同一个SPID中完成。 – zimdanen 2013-03-21 21:03:56

回答

1

如果您以前在同一个DbContext中加载了相同的Object实体,EF将返回具有陈旧值的缓存实例,并忽略从SQL返回的值。

最简单的办法是在返回前重新加载实体:

var result = db.Objects.Single(c => c.ObjectId == objectId); 
db.Entry(result).Reload(); 
return result; 
+1

这也是我的第一个想法,但OP看到查询在profiler中被执行。如果使用缓存值,则查询不应该被执行。 – 2013-03-22 19:28:28

+0

'Reload'可以工作,而且我在同一个'DbContext'中加载了'Object'。我不知道为什么它进入数据库,然后忽略结果并使用缓存值 - 因为这确实是发生了什么(即使我切换到“First”而不是“Single”)。看起来这里最好的做法是'重新加载'我早先在'DbContext'中提取的'Object'。感谢你! – zimdanen 2013-03-22 19:58:14

+0

@SebastianMeine:不幸的是,查询仍然会被执行,但是EF会把结果扔掉。 – 2013-03-22 20:01:21

0

这确实很奇怪。在SQL Server视图中,默认情况下不会持久化,因此会立即显示底层数据的更改。您可以在视图上创建聚集索引并有效地保留查询,但在这种情况下,数据会同步更新,因此您应该立即看到更改。

如果您使用快照隔离级别,您的更改可能不会立即对其他SPID可见,但由于您位于同一SPID并且不使用快照隔离,因此也不可能是罪魁祸首。

此时唯一剩下的就是应用程序层。你真的在调用堆栈中使用更高的Single调用结果还是会在某处丢失?我假设页面刷新使用不同的代码路径,这将解释为什么它在那里工作。

+0

我正在使用结果更新Web应用程序发出呼叫的数据网格中的那一行。刷新确实使用不同的代码路径(通过不同的服务操作加载整个网格)。 – zimdanen 2013-03-22 13:45:10

相关问题