0

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

[...]

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()を使用する場合、 GenericRepositoryInsertメソッドコードを以下で確認します

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

2 に答える 2

1

おそらく間違った DI (Ninject) 構成が問題を引き起こします。以下の解決策を確認してください。

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

.InRequestScope();実際、以前の構成では使用していません。そのため、不思議な行動を起こします。

しかし、その背後にある理由をまだ理解できていません。明確化歓迎。

Mystere Manの説明によると(問題: リポジトリとコントローラーの両方で UnitOfWork を使用しているため、2 つの異なるインスタンスがあり、各インスタンスには独自のコンテキストがありました。そのため、エンティティを 1 つのコンテキスト (内の 1 つ) に追加しました。別のコンテキストで SaveChanges を呼び出しましたが、その別のコンテキストには何も追加されていないため、何も起こりませんでした。

提案:リポジトリを InRequestScope にする必要はなく、UnitOfWork のみを作成する必要があります。これはコンテキストを保持するためです)。

したがって、最適なソリューションは以下のとおりです。

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

を使用せず_dbContext ?? Activator.CreateInstance<C>();に、Ninject を介して DbContext インスタンスを取得することはできますか?

はい、 MystereMan Suggestionによると、問題ありません。以下のソリューションを確認してください

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()。Controller がどのように構築され、インスタンスに渡されるかを調べると、問題の修正方法が決まります。

ちなみに、EF では既に暗黙のトランザクションが使用されているため、TransactionScope は通常は必要ありません。

また、ステートメントの使用については非常に注意します。そのブロックの外で UnitOfWork を使用しようとすると、重大なバグが発生する可能性があります。代わりに、UnitOfWork を作成したのは DI フレームワークであるため、UnitOfWork の破棄は DI フレームワークに任せます。

さらに言えば、Activator を使用する代わりに、DI フレームワークを使用して UoW でコンテキストを作成することもできます。

于 2013-01-13T01:44:40.207 に答える