EF返回旧值

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

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

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

this.context.someTable.Where(arg => arg.value == "value").Single(); 

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

 this.context.Entry(entity).Reload(); 

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

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

你不应该坚持上下文

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

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

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

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

但是如果你必须重新加载Update

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

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

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

 this.context.someTable.AsNoTracking().Where(arg => arg.value == "value").Single(); 

重要的方法调用是AsNoTracking

如果您使用MVVM,那么您可以这样做:您的视图绑定到您的视图模型,其属性类型为EntityViewModel(是实体的包装器)。 所有更改都会立即显示在EntityViewModel中。 如果要撤消更改 – 调用方法EntityViewModel.Undo()。 如果要将更改应用于实体 – 请调用EntityViewModel.Apply()。 然后你可以调用方法DbContext.SaveChanges()。

 public class Entity { public string Id { get; set; } public string State { get; set; } } public class EntityViewModel : ViewModelBase { private string _state; public EntityViewModel(Entity entity) { Entity = entity; _state = entity.State; } public string State { get { return _state; } set { if (value == _state) return; _state = value; base.OnPropertyChanged("State"); } } public Entity Entity {get; private set; } public void ApplyChanges() { Entity.State = _state; } public void Undo() { State = entity.State; } } 

这是一个很好的职责分工,适合MVVM。