EF返回旧值

时间:2015-01-20 09:48:46

标签: 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();

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

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

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

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

3 个答案:

答案 0 :(得分:8)

您不应该坚持上下文

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

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

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

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

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

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

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

答案 1 :(得分:3)

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

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

重要的方法是AsNoTracking

答案 2 :(得分:0)

如果您使用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。