EF7 DbContext处理

时间:2016-04-06 08:19:39

标签: c# entity-framework sqlite entity-framework-core

我正在构建一个使用WPF和EF7与SqLite的桌面应用程序。在我的服务类中,我注入了一个IContextScopeLocator实例,主要工作是创建和重用EF DbContexts的实例。

ContextScope

   public class ContextScope : IDisposable
{
    private readonly PrzylepaDbContext _context;

    public ContextScope(PrzylepaDbContext context)
    {
        _context = context;
    }

    public EventHandler OnDisposed { get; set; }

    public PrzylepaDbContext Context
    {
        get { return _context; }
    }

    public void Dispose()
    {
        OnDisposed.Invoke(this, EventArgs.Empty);
    }
}

ContextScopeLocator

    public class ContextScopeLocator : IContextScopeLocator
{
    private readonly IContextFactory _factory;

    public ContextScopeLocator(IContextFactory factory)
    {
        _factory = factory;
    }

    private PrzylepaDbContext _currentContext;
    private readonly List<ContextScope> _currentScopes = new List<ContextScope>();

    public ContextScope GetScope()
    {
        if (_currentContext == null)
        {
            //building new EF DbContext if nescesary
            _currentContext = _factory.Create();
        }

        var scope = new ContextScope(_currentContext);

        scope.OnDisposed += OnDisposed;
        _currentScopes.Add(scope);
        return scope;
    }

    private void OnDisposed(object sender, EventArgs eventArgs)
    {
        var scope = sender as ContextScope;
        Debug.Assert(_currentScopes.Contains(scope));
        _currentScopes.Remove(scope);

        if (_currentScopes.Count == 0)
        {
            _currentContext.Dispose();
            _currentContext = null;
        }
    }
}

然后在我的服务方法中我可以这样使用它:

public IEnumerable<Client> GetPublicClients()
    {
        using (var scope = _scopeLocator.GetScope())
        {
            return scope.Context.Clients.Where(x => x.IsPublic).IncludeStandard().ToList();
        }
    }

即使使用嵌套查询,我仍然可以获得相同的上下文。我不会从多个线程调用服务方法,所以我认为这种方法对我来说效果会更差。

然后在我的viewmodel类中,我按以下方式收到消息

  private void ClientModifiedMessageHandler(NotifyEntityModifiedMessage<Client> msg)
    {
        if (msg.EntityId == ModifiedOffer.ClientId)
        {
            var client = _clientService.GetById(ModifiedOffer.ClientId);               
            ModifiedOffer.Client = client; //exception
        }
    }

DbContext引发异常,用于从Db获取ModifiedOffer:

  

“无法跟踪实体类型'Przylepa.Data.Client'的实例,因为已经跟踪了具有相同键的此类型的另一个实例。对于新实体,请考虑使用IIdentityGenerator生成唯一键值。”

问题是旧的DbContext仍然存在,因为它在ModifiedOffer中订阅了PropertyChanged事件,即使它上面调用了Dispose()(DbContext._disposed为true)。

如何让这些DbContexts取消订阅这些事件,以便我可以用我的模型类实例做我想做的事情?谢谢

0 个答案:

没有答案