Reputation: 1322
I am facing a problem to save data using UnitOfWork. I mean I am unable to save data using UnitOFWork.Commit() from Controller class. My Implementation check bellow.
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
}
Now within 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();
}
[...]
When I use UnitOfWork.Commit(); within GenericRepository I am able to save data successfully. But When I use UnitOfWork.Commit(); withing Controller I am unable to save data.
Controller Code
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);
}
If I use UnitOfWork.commit() within Controller then GenericRepository Insert method code check bellow
public void Insert(E entity)
{
_dbSet.Add(entity);
UnitOfWork.GetContext.Entry(entity).State = System.Data.EntityState.Added;
}
As per my understanding this is a designing issue of UnitOfWork. Please help me to solve that.
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>();
Upvotes: 0
Views: 1185
Reputation: 1322
Probably Wrong DI (Ninject) Configuration create the problem. Solution check bellow.
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InRequestScope();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>().InRequestScope();
Actualy I don't use .InRequestScope();
in my previous configuration. that's why It create mysterious behavior.
But Still unable to understand the reason behind that. Clarification welcome.
According the clarification of Mystere Man (Problem: Since you use UnitOfWork both in your repository, and in your controller, you had two different instances, and each instance had its own context. So, you added the entities to one context (the one in your repository) but you called SaveChanges on a different context. Since that different context didn't have anything added to it, nothing happened.
Suggestion: you shouldn't need to make the repository InRequestScope, only the UnitOfWork, since that holds the context).
So the Best solution check bellow.
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InRequestScope();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
Without using _dbContext ?? Activator.CreateInstance<C>();
, can it be possible to get DbContext instance via Ninject ?
Yes it is poositble According to MystereMan Suggestion. Check the solution bellow
Ninject DI Configuration
kernel.Bind<MyDbContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
And within 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;
}
}
[...]
Upvotes: 1
Reputation: 93434
There's a lot of things you have left out of your question. It looks like you may be using some kind of dependency injection, if that's the case, what DI framework are you using, and how are your bindings declared?
The real problem here is, I think, that your repository is being created with a different UnitOfWork than the one which you are using to call Commit()
. Looking at how the Controller is constructed and passed the instances will determine how to fix the problem.
By the way, TransactionScope is generally not required with EF, since it uses an implied transaction already.
Also, i'd be very careful about that using statement. It can create a serious bug if you try to use the UnitOfWork outside that block. Instead, I would let my DI framework take care of disposing the UnitOfWork, since it's the one that created it.
For that matter, I would also use the DI framework to create the context in your UoW instead of using Activator.
Upvotes: 0