0

我在使用 UnitOfWork 保存数据时遇到问题。我的意思是我无法使用Controller 类中的UnitOFWork.Commit()保存数据。我的实施检查如下。

工作单位

public interface IUnitOfWork<C> :  IDisposable
{
        int Commit();
        C GetContext { get; set; }
        TransactionScope BeginTransaction();
} 

工作单位

   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();
        }

[...]

当我使用UnitOfWork.Commit(); GenericRepository中,我能够成功保存数据。但是当我使用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 Insert 方法代码检查如下

        public void Insert(E entity)
        {
            _dbSet.Add(entity);
            UnitOfWork.GetContext.Entry(entity).State = System.Data.EntityState.Added;
        }

据我了解,这是 UnitOfWork 的设计问题。请帮我解决这个问题。

IEmployee存储库

public interface IEmployeeRepository : IRepository<EmployeeModel>
{

}

public class EmployeeRepository : RepositoryBase<MyDbContext, EmployeeModel>, IEmployeeRepository
{
    public EmployeeRepository(IUnitOfWork<MyDbMContext> unitOfWork)
        : base(unitOfWork)
    {

    }
}

NinjetDI配置

kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
kernel.Bind<ICountryRepository>().To<CountryRepository>();
kernel.Bind<IUserProfileRepository>().To<UserProfileRepository>();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
4

2 回答 2

1

可能是错误的 DI (Ninject) 配置造成了问题。解决方案检查如下。

kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InRequestScope();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>().InRequestScope();

实际上我没有.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 实例?

是的,根据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;
            }

        }
[...]
于 2013-01-13T11:52:17.207 回答
0

你有很多问题没有解决。看起来您可能正在使用某种依赖注入,如果是这种情况,您使用的是什么 DI 框架,以及您的绑定是如何声明的?

我认为,这里真正的问题是,您的存储库是使用与您用来调用的不同的 UnitOfWork 创建的Commit()。查看控制器的构造和传递实例将确定如何解决问题。

顺便说一句,EF 通常不需要 TransactionScope,因为它已经使用了隐含的事务。

另外,我会非常小心那个 using 语句。如果您尝试在该块之外使用 UnitOfWork,它可能会产生严重的错误。相反,我会让我的 DI 框架负责处理 UnitOfWork,因为它是创建它的那个。

就此而言,我还将使用 DI 框架在您的 UoW 中创建上下文,而不是使用 Activator。

于 2013-01-13T01:44:40.207 回答