我一直试图在WPF的工作单元/存储库模式中使用DI。我当前遇到的问题是,如果我对_UserRepo.Add(User)之类的存储库进行了调用,并且引发了异常。每次对存储库的新调用都会引发异常,因为上下文永远不会被丢弃。
我尝试过的事情
工作单位
public class UnitOfWork : IUnitOfWork
{
private DbContextTransaction _trans;
private BomConfiguratorContext _context;
public UnitOfWork(BomConfiguratorContext context)
{
_context = context;
_trans = context.Database.BeginTransaction();
}
public void Dispose()
{
try
{
_context.SaveChanges();
_trans.Commit();
}
catch (Exception)
{
_trans.Rollback();
}
finally
{
_context.Dispose(); //This obviously does not work
}
}
}
工作单位工厂
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private BomConfiguratorContext _context;
public UnitOfWorkFactory(BomConfiguratorContext context)
{
_context = context;
}
public UnitOfWork Create()
{
return new UnitOfWork(_context);
}
}
我的通用存储库
public interface IRepository<TEntity> where TEntity : class
{
void Add(TEntity entity);
void AddRange(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void RemoveRange(IEnumerable<TEntity> entities);
TEntity Get(int id);
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
void Update(TEntity entity);
}
通用存储库实施
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly BomConfiguratorContext Context;
public Repository(BomConfiguratorContext context)
{
Context = context;
}
public virtual void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
Context.Set<TEntity>().AddRange(entities);
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().Where(predicate);
}
public TEntity Get(int id)
{
return Context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
public void Remove(TEntity entity)
{
Context.Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
Context.Set<TEntity>().RemoveRange(entities);
}
public void Update(TEntity entity)
{
Context.Set<TEntity>().Attach(entity);
Context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
}
用户存储库
public class UserRepository : Repository<User>,IUserRepository
{
public UserRepository(BomConfiguratorContext context)
:base(context)
{
}
}
用例
using (var UOW = _UnitOfWorkFactory.Create())
{
//Submit the user
_UserRepository.Add(ExampleNewUser);
}
因此,当前我正在使用MVVM Light来完成我的所有DI工作,现在我了解到使用mvvm light只能注入单例范围。因此,我很确定我最终将不得不切换到Ninject之类的东西,以便可以利用它们的.InTransientScope或.InNamedScope(根据我一直在阅读的内容)。
显然,以上代码不适用于MVVM Light,因为从未适当处置上下文。
问题
所以我要问的是我是否要换用Ninject并开始将Context注入这些存储库/工作单元中。如何正确配置它以AWLAYS在我的工作单元中为存储库注入新的上下文。
我读到Ninject MVC具有.InRequestScope可以完全解决问题。但是WPF呢?您如何实现相同的注射?
我似乎找不到确切的解决方案/模式,或者也许有更好的方法可以做到这一点?任何建议和帮助将不胜感激。
答案 0 :(得分:1)
我对这个问题的解决方案是创建一个ContextFactory。
界面
public interface IContextFactory
{
BomConfiguratorContext Create();
BomConfiguratorContext Get();
}
上下文工厂
工厂允许我获取现有上下文或创建新上下文。
public class ContextFactory : IContextFactory
{
private BomConfiguratorContext _context;
public ContextFactory(BomConfiguratorContext context)
{
_context = context;
}
public BomConfiguratorContext Create()
{
_context = new BomConfiguratorContext();
return _context;
}
public BomConfiguratorContext Get()
{
return _context;
}
}
新基本存储库
通过调用ContextFactory.Get()方法,我使用了缓存的上下文,而不是创建一个新的上下文。
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly IContextFactory ContextFactory;
public Repository(IContextFactory factory)
{
ContextFactory = factory;
}
public virtual void Add(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
ContextFactory.Get().Set<TEntity>().AddRange(entities);
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return ContextFactory.Get().Set<TEntity>().Where(predicate);
}
public TEntity Get(int id)
{
return ContextFactory.Get().Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return ContextFactory.Get().Set<TEntity>().ToList();
}
public void Remove(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
ContextFactory.Get().Set<TEntity>().RemoveRange(entities);
}
public void Update(TEntity entity)
{
ContextFactory.Get().Set<TEntity>().Attach(entity);
ContextFactory.Get().Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
}
新工作单位工厂
当工厂为Create()方法时,我调用上下文工厂的Create()方法来创建新的上下文。
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private IContextFactory _contextFactory;
public UnitOfWorkFactory(IContextFactory factory)
{
_contextFactory = factory;
}
public UnitOfWork Create()
{
return new UnitOfWork(_contextFactory.Create());
}
}
通过这种方式,我现在可以将上下文工厂注入到我所有的存储库中。我试图在原始问题中使用上面提到的Ninject范围,但最终导致在注入两个单独的上下文时出现问题,一个在我的工作单位工厂中,另一个在我的存储库中。