使用EntityFramework Core,我有以下代码:
task2
两个断言均失败。似乎在第二次调用中,div
仍返回旧的var theStudent = new Student();
theStudent.Title = "Mehran"
theStudent.Status = 1
mainDbContext.Set<Student>().Add(theStudent);
await mainDbContext.SaveChangesAsync();
// In reality data is changed by another program. To simulate it here I alter the data by another dbcontext and raw SQL
using (var utilDbContext = new MelkRadarDbContext())
{
var command = " update dbo.Student set status=2 where Id=@p0";
utilDbContext.Database.ExecuteSqlCommand(command, theStudent.Id);
}
var reloadedStudent = await mainDbContext.Set<Student>()
.Where(s => s.Id == theStudent.Id)
.FirstOrDefaultAsync();
Assert.AreNotEqual(reloadedStudent, student);
Assert.AreEqual(reloadedStudent.Status, 2);
对象为mainDbContext
,并且没有从数据库中加载它来获取最新数据。为什么呢?我应该怎么做才能在数据库上获取最新数据?
答案 0 :(得分:2)
您有两个选择:
[不推荐]对每个实体使用Reload
或ReloadAsync
方法:
await mainDbContext.Entry(theStudent).ReloadAsync();
由于必须分别为每个实体调用此方法,因此当您需要重新加载一堆实体时,效率非常低。
[推荐]创建一个新的DbContext
。这是解决陈旧数据问题的最终方法。
DbContext
被设计为短命的。它们实现了Unit Of Work模式,因此建议为每一批相关操作(业务交易)都创建一个DbContext
-例如,用户操作(按“保存”按钮)。尽管对于每个HTTP请求(在Web应用程序或Web服务的上下文中)只有一个DbContext
的通用做法可以满足此要求,但是有时您需要在一个请求中执行多个“操作批处理”。那是您需要考虑创建更多DbContext
的时候了。
为一系列操作保留一个DbContext
的全部要点是缓存,跟踪和延迟加载 。每当您需要重新加载数据时,很明显,您从此位置都不需要这些功能。因此,使用新的DbContext
很有意义。
一个很好的答案是,为什么首先需要新数据?如果您需要根据数据做出关键决策,并且依赖过时的数据会导致数据存储不一致,那么即使刷新实体也无济于事。在这种情况下,您需要使用更强大的机制,例如锁(数据库或其他方式)来防止陈旧数据。
注意:在 Entity Framework 6 中,有一种Refresh
方法可用于立即刷新所有对象。该方法在 Entity Framework Core 中不可用,因为它并没有被证明有用。
答案 1 :(得分:0)
DbContext为要求从数据存储中检索的对象提供了一级缓存。随后对同一对象的请求将返回缓存的对象,而不是执行另一个数据库请求。
该对象已在主上下文中缓存,并且尚未更新,因为在更新对象时使用了不同的上下文,因此可以在加载之前使用AsNoTracking忽略缓存,但对于您而言,对象已初始化,然后附加到上下文(已缓存),您可以执行的操作是分离EntityState对象,以便上下文不再跟踪该对象,然后可以再次加载它,希望对您有用。
mainDbContext.Entry(theStudent).State = EntityState.Detached;
var reloadedStudent = await mainDbContext.Set<Student>()
.Where(s => s.Id == theStudent.Id)
.FirstOrDefaultAsync();