我遇到使用UnitOfWork保存数据的问题。我的意思是我无法使用Controller类中的 UnitOFWork.Commit()来保存数据。我的实施检查如下。
IUnitOfWork
public interface IUnitOfWork<C> : IDisposable
{
int Commit();
C GetContext { get; set; }
TransactionScope BeginTransaction();
}
的UnitOfWork
public class UnitOfWork<C> : IUnitOfWork<C> where C : DbContext
{
private bool _disposed;
private readonly C _dbContext = null;
private TransactionScope _transaction;
public UnitOfWork()
{
GetContext = _dbContext ?? Activator.CreateInstance<C>();
}
public int Commit()
{
return GetContext.SaveChanges();
}
public C GetContext
{
get;
set;
}
public TransactionScope BeginTransaction()
{
if (null != _transaction)
{
_transaction = new TransactionScope();
}
return _transaction;
}
#region IDisposable Members
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (null != _transaction)
{
_transaction.Dispose();
}
if (null != _dbContext)
{
_dbContext.Dispose();
}
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
现在在 RepositoryBase / GenericRepository
中public abstract class RepositoryBase<C, E> : IRepository<E> where E : class where C : DbContext
{
private readonly IDbSet<E> _dbSet;
protected RepositoryBase(IUnitOfWork<C> unitOfWork)
{
UnitOfWork = unitOfWork;
_dbSet = UnitOfWork.GetContext.Set<E>();
}
protected IUnitOfWork<C> UnitOfWork
{
get;
private set;
}
#region IRepository<E> Members
public void Insert(E entity)
{
_dbSet.Add(entity);
UnitOfWork.GetContext.Entry(entity).State = System.Data.EntityState.Added;
UnitOfWork.Commit();
}
[...]
当我在 GenericRepository 中使用 UnitOfWork.Commit(); 时,我能够成功保存数据。但是当我使用 UnitOfWork.Commit(); 和控制器时,我无法保存数据。
控制器代码
private readonly IEmployeeRepository _employeeRepository;
public EmployeeController(IEmployeeRepository employeeRepositoty, IUnitOfWork<MyDbContext> unitOfWork)
{
UnitOfWork = unitOfWork;
this._employeeRepository = employeeRepositoty;
}
[HttpPost]
public ActionResult Create(EmployeeModel employeemodel)
{
if (ModelState.IsValid)
{
using (UnitOfWork)
{
_employeeRepository.Insert(employeemodel);
UnitOfWork.Commit(); //OR UnitOfWork.GetContext.SaveChanges();
}
return RedirectToAction("Index");
}
return View(employeemodel);
}
如果我在Controller中使用 UnitOfWork.commit(),那么 GenericRepository 插入方法代码检查
public void Insert(E entity)
{
_dbSet.Add(entity);
UnitOfWork.GetContext.Entry(entity).State = System.Data.EntityState.Added;
}
根据我的理解,这是UnitOfWork的设计问题。请帮我解决这个问题。
IEmployeeRepository
public interface IEmployeeRepository : IRepository<EmployeeModel>
{
}
public class EmployeeRepository : RepositoryBase<MyDbContext, EmployeeModel>, IEmployeeRepository
{
public EmployeeRepository(IUnitOfWork<MyDbMContext> unitOfWork)
: base(unitOfWork)
{
}
}
NinjetDIConfiguration
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
kernel.Bind<ICountryRepository>().To<CountryRepository>();
kernel.Bind<IUserProfileRepository>().To<UserProfileRepository>();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
答案 0 :(得分:1)
可能错误的DI(Ninject)配置会产生问题。解决方法检查下面。
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InRequestScope();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>().InRequestScope();
Actualy我在之前的配置中没有使用.InRequestScope();
。这就是它创造神秘行为的原因。
但仍然无法理解背后的原因。澄清欢迎。
根据 Mystere Man 的澄清(问题:)因为您在存储库和控制器中都使用UnitOfWork,所以您有两个不同的实例,每个实例都有因此,您将实体添加到一个上下文(存储库中的一个上下文),但是您在另一个上下文中调用了SaveChanges。由于不同的上下文没有添加任何内容,所以没有任何事情发生。
建议:您不需要创建存储库InRequestScope,只需要使用UnitOfWork,因为它保存了上下文)。
所以最佳解决方案检查如下。
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InRequestScope();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
不使用_dbContext ?? Activator.CreateInstance<C>();
,是否可以通过Ninject获取DbContext实例?
是的,它是poositble根据 MystereMan 建议。检查下面的解决方案
Ninject DI配置
kernel.Bind<MyDbContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
在 UnitOfWork
中 public class UnitOfWork<C> : IUnitOfWork<C> where C : DbContext
{
private readonly C _dbcontext;
public UnitOfWork(C dbcontext)
{
_dbcontext = dbcontext;
}
public int Commit()
{
return _dbcontext.SaveChanges();
}
public C GetContext
{
get
{
return _dbcontext;
}
}
[...]
答案 1 :(得分:0)
你的问题遗留了很多东西。看起来你可能正在使用某种依赖注入,如果是这种情况,你使用什么DI框架,以及你的绑定是如何声明的?
我认为,真正的问题是,您的存储库是使用与您用于调用Commit()
的UnitOfWork不同的UnitOfWork创建的。查看Controller如何构建并传递实例将决定如何解决问题。
顺便说一下,EF通常不需要TransactionScope,因为它已经使用了隐含的事务。
另外,我会非常小心使用声明。如果您尝试在该块之外使用UnitOfWork,它可能会产生严重的错误。相反,我会让我的DI框架负责处理UnitOfWork,因为它是创建它的那个。
就此而言,我还会使用DI框架在您的UoW中创建上下文而不是使用Activator。