EF returns old values

前端 未结 3 1974
甜味超标
甜味超标 2020-12-18 02:25

I\'m using EF6 + WPF with MVVM design pattern in my desktop application. I\'m using also Autofac as DI container.

I read a lot about EF context lifetime management

相关标签:
3条回答
  • 2020-12-18 02:45

    If you use MVVM then you can do: your view bind to your view model with property type EntityViewModel (is a wrapper for the Entity). All changes immediately appear in the EntityViewModel. If you want to undo changes - invoke method EntityViewModel.Undo(). If you want to apply the changes to the entity - invoke EntityViewModel.Apply(). Then you can invoke method 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;
        }
    }
    

    This is a good division of responsibilities, which fits into the MVVM.

    0 讨论(0)
  • 2020-12-18 02:46

    You shouldn't persist a context

    I would recommend you abandon the single shared context. I did this recently for a large WPF application. An EF context is designed to be a unit-of-work, you should use it and then call .Dispose(). If you need to read in relationship properties eagerly, you should use .Include() hints. You should construct your contexts in a using block so you know where you lose scope, and to ensure the context is disposed.

    You will find that performance of EF can actually diminish as it needs to refer to its internal cache and state. I have found bulk data insert patterns deteriorate if a shared context is used. EF doesn't perform as well as an RDBMS.

    As you have experienced, you can persist the context and benefit from cached entities, but if that's becoming a pain, due to the nature of your system and requirements of the user, you are not really benefiting from the caching anymore. Your backing RDBMS should be fast enough. As soon as you cache in any way (including EF second-level caching and ASP.NET Output Caching), you immediately need to plan how to expire your cached entities. This adds a lot more work for your coders, and gives your systems spectacular new ways to fail.

    For instance, consider that a benefit of EF is the automatic resolution of relationship properties. You can be seamlessly reaching across a graph of data until you hit an entity which is cached and stale. In such circumstances, it is difficult to expire the cache before retrieving such entities.

    But if you must reload on Update

    If you really don't want to change your architecture to the Microsoft recommended/intended way. I suggest you keep track of all open contexts (adding to static collection on construction, removing on dispose, double-check with finalizer pattern, and finalizer suppression on dispose), and implement some generic code in the save pipeline (there are a few ways of doing this) which attempts to reload the entity across all open contexts. This is an proactive way of expiring your EF entity caches. This may affect performance on larger collections, but you could have a whitelist or blacklist of entities to process, rather than processing all saved entities.

    Personally, I'm glad I made the change (restructuring to short-lived contexts), long term there are huge benefits in terms of code maintainability and system stability.

    0 讨论(0)
  • 2020-12-18 03:06

    Following method forces EF to requery the query to the database and do not cache the result:

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

    The important method call is AsNoTracking

    0 讨论(0)
提交回复
热议问题