EF返回旧值

rra*_*ski 6 c# entity-framework mvvm

我在我的桌面应用程序中使用EF6 + WPF和MVVM设计模式.我也使用Autofac作为DI容器.

我读了很多关于EF上下文生命周期管理的内容,我决定只为单一视图模型实例提供一个EF上下文实例.我发现了一些关于这种方法的有趣文章,所以我认为这只是管理EF上下文的好方法.我使用Autofac来管理EF生命周期,因此每次创建新的视图模型时,都只会创建一个新的EF上下文.

但当然,我遇到了一个问题.我的大多数EF查询都运行良好,但以下查询始终返回旧(缓存)值.每次按下"执行"按钮时都会调用此查询,因此每个视图/视图模型有很多执行

this.context.someTable.Where(arg => arg.value == "value").Single();
Run Code Online (Sandbox Code Playgroud)

我知道我总是可以使用以下代码重新加载实体

this.context.Entry(entity).Reload();
Run Code Online (Sandbox Code Playgroud)

但对我来说这不是一个好的解决方案.我也知道,如果我处理当前上下文并在下一个查询之前重新创建,我将始终接收当前值.但是这种方法与每种视图模型方法的一个上下文冲突.

我应该修复/更改什么以避免EF缓存问题并且仍然具有良好的性能.

Tod*_*odd 8

你不应该坚持上下文

我建议你放弃单一的共享上下文.我最近为大型WPF应用程序做了这个.EF上下文被设计为一个工作单元,您应该使用它然后调用.Dispose().如果您需要热切地阅读关系属性,则应使用.Include()提示.您应该在using块中构造上下文,以便知道丢失范围的位置,并确保处理上下文.

你会发现EF的性能实际上可以减少,因为它需要引用它的内部缓存和状态.我发现如果使用共享上下文,批量数据插入模式会恶化.EF的性能不如RDBMS.

正如您所经历的那样,您可以保留上下文并从缓存实体中受益,但如果由于系统的性质和用户的要求而变得很痛苦,那么您不再真正受益于缓存.您的支持RDBMS应该足够快.只要以任何方式缓存(包括EF二级缓存和ASP.NET输出缓存),您就需要立即计划如何使缓存的实体过期.这为您的编码人员增加了更多工作,并为您的系统提供了一种全新的失败方式.

例如,考虑EF的一个好处是自动解决关系属性.您可以无缝地跨越数据图表,直到您遇到缓存和陈旧的实体.在这种情况下,在检索这样的实体之前很难使缓存失效.

但是,如果您必须重新加载更新

如果您确实不想将您的体系结构更改为Microsoft建议/预期的方式.我建议你跟踪所有打开的上下文(添加到构造中的静态集合,删除处置,使用终结器模式进行双重检查,以及对dispose进行终结器抑制),并在save管道中实现一些通用代码(有几种方法)执行此操作)尝试在所有打开的上下文中重新加载实体.这是使EF实体缓存过期的主动方式.这可能会影响较大集合的性能,但您可以使用白名单或黑名单来处理实体,而不是处理所有已保存的实体.

就个人而言,我很高兴我做出了改变(重组为短命境),从长远来看,在代码可维护性和系统稳定性方面有很大的好处.


Mic*_*ger 7

以下方法强制 EF 重新向数据库查询查询并且不缓存结果:

this.context.someTable.AsNoTracking().Where(arg => arg.value == "value").Single();
Run Code Online (Sandbox Code Playgroud)

重要的方法调用是AsNoTracking