我正在构建一个使用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取消订阅这些事件,以便我可以用我的模型类实例做我想做的事情?谢谢