Following is my code. I want to know it is true or not.
public interface IRepository<T> : IDisposable
{
IQueryable<T> GetAll();
T Update(T entity);
T Insert(T entity);
T GetById(T entity);
void Delete(T entity);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly SchoolDBEntities _context;
public Repository(SchoolDBEntities context)
{
_context = context;
}
public IQueryable<T> GetAll()
{
return _context.Set<T>();
}
public T Update(T entity)
{
var result = _context.Set<T>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
return result;
}
public T Insert(T entity)
{
return _context.Set<T>().Add(entity);
}
public T GetById(T entity)
{
return _context.Set<T>().Find(entity);
}
public void Delete(T entity)
{
_context.Set<T>().Remove(entity);
}
public void Save()
{
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
The problem is, I don't know when and where to call the Save and Dispose methods.
Don't do dispose in IRepository<T>
Try UnitOfWork pattern like this
public interface IUnitOfWork : IDisposable
{
IRepository<Cart> CartRepository { get; }
IRepository<Product> ProductRepository { get; }
void Save();
}
public class UnitOfWork : IUnitOfWork
{
readonly SqlDbContext _context;
public UnitOfWork()
{
_context = new SqlDbContext();
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Save()
{
_context.SaveChanges();
}
public IGenericRepository<Cart> CartRepository
{
get { return new Repository<Cart>(_context); }
}
public IGenericRepository<User> UserRepository
{
get { return new Repository<User>(_context); }
}
}
You can call it like this
using (_unitOfWork)
{
var p = _unitOfWork.ProductRepository.SingleOrDefault(p => p.Id == productId);
_cartRepository.Add(p);
_unitOfWork.Save();
}
I think it depends on the way you use this repo.
So save when you want to save and dispose when you want to finish your work ... on application close etc..
As you use a Unit of Work pattern here, obviously you should call Save method if user (of a repository) send save changes command. It could be a person clicking Apply changes button on one of your Edit forms or other part of your application which handles some transaction logic and saves/discards changes based on it. So basically, when the logical set of changes is ready to be save, Repository takes care of it.
Related
I am trying to implement UOW with repository pattern in my application.
While the independent repository is in place, but while multiple repositories in one transaction (UOW) is driving me crazy.
EF Relation One Customer - Many CustomerContacts
IUnitOfWork
public interface IUnitOfWork
: IDisposable
{
void InitTransaction();
void Rollback();
void CommitTransaction();
}
BaseUOW
public class UnitOfWork :
IUnitOfWork
{
protected DbContextTransaction _transaction;
#region IUnitOfWork
public void CommitTransaction()
{
_transaction.UnderlyingTransaction.Commit();
}
public void Rollback()
{
_transaction.UnderlyingTransaction.Rollback();
}
#endregion IUnitOfWork
}
CustomerUOW
public class CustomerUOW
: UnitOfWork
{
private IRepository<CustomerRepository> _customerRepository;
private IRepository<CustomerContactRepository> _customerContactRepository;
public BranchUOW(IRepository<CustomerRepository> customerRepository,
IRepository<CustomerContactRepository> customerContactRepository)
{
_customerRepository= customerRepository;
_customerContactRepository= customerContactRepository;
}
public override void InitTransaction()
{
_transaction.Commit();
}
}
How do I implement my CustomerUOW so that Customer &
CustomerContact repository share the same DbContext & goes in one
transaction??
Note: Each repository has an implementation of CRUD in their separate class. like
public class EntityRepository<C, T>
: BaseRepository<FoodieTenantContext, T>
where T : class
where C : CustomerContext
{
private DbSet<T> _dataSet
{
get
{
return _ctx.Set<T>();
}
}
public EntityRepository(FoodieTenantContext ctx)
: base(ctx)
{
}
public override void Add(T entity)
{
_dataSet.Add(entity);
}
public override void Delete(T entity)
{
throw new NotImplementedException();
}
public override IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).ToList<T>();
}
public override IEnumerable<T> GetAll()
{
return _dataSet.ToList<T>();
}
public override IQueryable<T> GetQuery()
{
return _dataSet;
}
public override int Save()
{
return _ctx.SaveChanges();
}
public override T Single(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).SingleOrDefault();
}
public override void Update(T entity)
{
_dataSet.Attach(entity);
_ctx.Entry<T>(entity).State = EntityState.Modified;
}
}
Thanks
On way would be to provide a Func<FoodieTenantContext, IRepository<CustomerContactRepository>> in your CustomerUow
public abstract class UnitOfWork : IUnitOfWork
{
public UnitOfWork(FoodieTenantContext context)
{
this.Context = context;
}
// ... rest of the class
}
// usage could be like the following
public class CustomerUOW : UnitOfWork
{
public CustomerService(Func<FoodieTenantContext, IRepository<CustomerRepository>> customerRepo
, Func<FoodieTenantContext, IRepository<CustomerContactRepository>> contactRepo
, FoodieTenantContext context)
: (context)
{
_customerRepo = customerRepo(context);
_contactRepo = contactRepo(context);
}
}
Another option would be to create a RepositoryFactory, but this would mean you would have to expose a Context property from IRepository<T>
public class RepositoryFactory
{
IServiceProvider _ioc; // This would be your IoC/DI Container
public RepositoryFactory(IServiceProvider ioc)
{
_ioc = ioc;
}
// Resolve T passing in the provided `FoodieTenantContext` into the constructor
public IRepository<T> CreateRepository<T>(FoodieTenantContext context) =>
_ioc.Resolve<T>(context);
}
Another solution could be (my least favourite) would be to expose methods in a RepositoryFactory for each type of IRepository<T>
public class RepositoryFactory
{
public IRepository CreateCustomerContactRepository(FoodieTenantContext context) =>
return new CustomerContactRepository(context);
}
Registering Func in Castle.Windsor
As per comment, to register Func<T> in Castle.Windsor you can try something like the following which is a modified version of Anton's answer to Func injecting with Windsor container question.. (I am not able to test this right now)
Container.Register(
Component.For<Func<FoodieTenantContext, IRepository<CustomerRepository>>>()
.Instance((FoodieTenantContext context) => Container.Resolve<IRepository<CustomerRepository>>(new {context = context}))
)
Otherwise you could try playing around with AsFactory(). For more info read Windsor documentation
And as a last resort, you can always fallback to manually creating a factory or switching IoC/DI containers that support Func<[TIn1, TIn2, ...], T> out of the box, or at least natively.
It's a week I have been dealing with Repository pattern, somehow I have implemented something, a generic repository:
private CentralEntities db = null;
private DbSet<T> table = null;
public RepositoryTest()
{
this.db = new CentralEntities();
table = db.Set<T>();
}
public RepositoryTest(CentralEntities db)
{
this.db = db;
table = db.Set<T>();
}
public IEnumerable<T> SelectAll()
{
return table.Take(10).ToList();
}
Here is my IRepository:
public interface IRepositoryTest<T> where T:class
{
IEnumerable<T> SelectAll();
}
Here in my Controller I implemented like the following and it works:
public class DashbrdController : Controller
{
IRepositoryTest<Event> _repository = null;
public DashbrdController(IRepositoryTest<Event> _repository)
{
this._repository = _repository;
}
public DashbrdController()
{
this._repository = new RepositoryTest<Event>();
}
public ActionResult DashBrd()
{
var rslt= _repository.SelectAll().Take(10);
return View(rslt);
}
}
First I do not how to implement Iunitofwork and UnitOfWork, and second apart from creating a single gate for update or insert, whats the usage of UnitOfWork? what kind of problem can it solve in the above example?
Please refer to the section below for detail understanding of UOW and Repository:
1) You create Generic Repository (The base of all the data source):
public class GenericRepository : IGenericRepository where T :
class
{
protected DbContext _entities;
protected readonly IDbSet<T> _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _dbset.AsEnumerable();
}
public IEnumerable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IEnumerable<T> query = _dbset.Where(predicate).AsEnumerable();
return query;
}
public virtual T GetSingle(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
T query = _dbset.Where(predicate).FirstOrDefault();
return query;
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = EntityState.Modified;
}
public virtual void Attach(T entity)
{
_dbset.Attach(entity);
}
public virtual void Save()
{
_entities.SaveChanges();
}
}
2) Then you create a Unit Of Work (Generic that adds the instance of Repository)
public sealed class GenericUnitOfWork : IGenericUnitOfWork, IDisposable
{
private ApplicationDbContext entities = null;
private ApplicationUserManager _userManager;
public GenericUnitOfWork()
{
entities = new ApplicationDbContext();
}
public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public IGenericRepository<T> Repository<T>() where T : class
{
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as IGenericRepository<T>;
}
IGenericRepository<T> repo = new GenericRepository<T>(entities);
repositories.Add(typeof(T), repo);
return repo;
}
public int Commit()
{
return entities.SaveChanges();
}
private bool disposed = false;
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
entities.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
3) Then you call UnitOfWork from your controller, that creates instance of Repository in Generic Form
public class DashbrdController : Controller
{
private GenericUnitOfWork uow = null;
public DashbrdController()
{
uow = new GenericUnitOfWork();
}
public ActionResult DashBrd()
{
var rslt = uow.Repository<Event>().GetAll().ToList();
return View(rslt);
}
}
The unit of work class coordinates the work of multiple repositories by creating a single database context class shared by all of them.
For a specific user action (say adding a event), all the transactions like insert/update/delete and so on are done in one single transaction, rather then doing multiple database transactions. This means, one unit of work here involves insert/update/delete operations, all in one single transaction.
Please make the interfaces with the implementation classes provided above. Let me know if problem occurs in that.
Hope if helps.
I am working on crud operations in mvc 4.0 with unitofwork and generic repository with Ninject for DI.
I am able to get a particular record from a table, I am even able to get all the records from the table.
but I am not able to insert a new record in the database table. I am not getting any error/exception and it is running each statement
cleanly but there is no effect in database below is my controller where I am using the repository and unitof work.
Can somebody tell me where I am wron or what code/statements I have left in this code. I ahve checked it lot of time and I am stucked now.
Not getting the problem
Controller:
private IUnitOfWork _unitOfWork;
private IRepository<tbl_Employee> _Repo;
private IRepository<tbl_Department> _Department;
public HomeController( IUnitOfWork UOW, IRepository<tbl_Employee> Repository, IRepository<tbl_Department> Depart)
{
this._unitOfWork = UOW;
this._Repo = Repository;
this._Department = Depart;
}
//This runs successfully and gets all the records in the view page and I am displaying all records using foreach in div structure
public ActionResult Index()
{
EmployeeModel ObjModel = new EmployeeModel();
ObjModel.Employees = this._Repo.GetALL();
//ObjModel.Employees = this._Employee.GetEmployees();
return View(ObjModel);
}
//This also runs successfully and it brought me a single record on selection of particular record from employee listing.
public ActionResult EmployeeDetail(string id)
{
EmployeeDetailModel ObjModel = new EmployeeDetailModel();
if (!string.IsNullOrEmpty(id))
{
var Employee = this._Repo.Find(Convert.ToInt32(id));
if (Employee != null)
{
ObjModel.InjectFrom(Employee);
}
}
return View(ObjModel);
}
// Here is the problem . Not able to insert the record. The model object is not empty . I have checked it and there is no error.It brought me a message
"Employee Created Successfully but in database there is no record.
public ActionResult SaveEmployee(EmployeeDetailModel Model)
{
string Msg = string.Empty;
try
{
tbl_Employee ObjEmployee = new tbl_Employee();
ObjEmployee.InjectFrom(Model);
if (Model.Male)
{
ObjEmployee.Sex = "m";
}
else
{
ObjEmployee.Sex = "f";
}
ObjEmployee.Department_Id = Model.Dept_id;
ObjEmployee.Salary = Convert.ToInt32(Model.Salary);
this._Repo.Insert(ObjEmployee);
this._unitOfWork.Commit();
Msg = "Employee Created Successfully";
}
catch
{
Msg = "Error occurred while creating the employee, Please try again.";
}
return Json(new { Message = Msg });
}
/// Repository interface
public interface IRepository<T> where T : class
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
T Find(int key);
IEnumerable<T> GetALL();
}
Repository class
public class Repository<T> : Connection, IRepository<T> where T : class
{
private readonly DbSet<T> _dbSet;
public Repository()
{
_dbSet = _dbContext.Set<T>();
}
public void Insert(T entity)
{
_dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public void Update(T entity)
{
var updated = _dbSet.Attach(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
//_dataContext.Entry(item).State = EntityState.Modified;
}
public T Find(int Key)
{
var dbResult = _dbSet.Find(Key);
return dbResult;
}
public IEnumerable<T> GetALL()
{
return _dbSet;
}
}
UnitofWork Interface
public interface IUnitOfWork : IDisposable
{
void Commit();
}
Unit of work class
public class UnitOfWork : Connection, IUnitOfWork
{
private bool _disposed;
public void Commit()
{
_dbContext.SaveChanges();
}
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue to prevent finalization code for object from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!_disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
if (_dbContext != null)
{
_dbContext.Dispose();
}
}
}
_disposed = true;
}
}
My UnitofWork and Repository class derives from connection class where dbcontext is defined.
public abstract class Connection
{
protected db_TestEntities _dbContext;
public Connection()
{
this._dbContext = new db_TestEntities();
}
}
Is it that my dbContext is creating a new instance everytime like explained Here
and if yes then how can I resolve it.
tbl_Employee ObjEmployee = new tbl_Employee();
ObjEmployee.InjectFrom(Model);
if (Model.Male)
{
ObjEmployee.Sex = "m";
}
else
{
ObjEmployee.Sex = "f";
}
ObjEmployee.Department_Id = Model.Dept_id;
ObjEmployee.Salary = Convert.ToInt32(Model.Salary);
this._Repo.Insert(ObjEmployee);
After this, you should see your object mapped by EF in local memory.
this._unitOfWork.Commit();
Here your object should be pushed to database. dbContext.SaveChanges() return number of changed records which should be in your case 1.
Msg = "Employee Created Successfully";
Update:
So the problem is in your Connection class as you suggested.
I would create your DbContext in one place and then pass it to repository and unit of work. You could also create DbContext in unit of work constructor and then pass UOW to repository. This is one of my older implementation of this:
public class EntityFrameworkUnitOfWork : IUnitOfWork
{
private ForexDbContext dbContext;
internal ForexDbContext DbContext
{
get { return dbContext ?? (dbContext = new ForexDbContext()); }
}
internal DbSet<T> Set<T>()
where T : class
{
return DbContext.Set<T>();
}
public void Dispose()
{
if(dbContext == null) return;
dbContext.Dispose();
dbContext = null;
}
public void SaveChanges()
{
int result = DbContext.SaveChanges();
}
public ITransaction BeginTransaction()
{
return new EntityFrameworkTransaction(DbContext.BeginTransaction());
}
}
public class ContactsRepositoryWithUow : IRepository<Contact>
{
private SampleDbEntities entities = null;
public ContactsRepositoryWithUow(SampleDbEntities _entities)
{
entities = _entities;
}
public IEnumerable<Contact> GetAll(Func<Contact, bool> predicate = null)
{
if (predicate != null)
{
if (predicate != null)
{
return entities.Contacts.Where(predicate);
}
}
return entities.Contacts;
}
public Contact Get(Func<Contact, bool> predicate)
{
return entities.Contacts.FirstOrDefault(predicate);
}
public void Add(Contact entity)
{
entities.Contacts.AddObject(entity);
}
public void Attach(Contact entity)
{
entities.Contacts.Attach(entity);
entities.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
public void Delete(Contact entity)
{
entities.Contacts.DeleteObject(entity);
}
}
Please find answer in below link for more details
Crud Operation with UnitOfWork
I have a generic Repository like this:
public interface IRepository<TEntity> where TEntity :class
{
IEnumerable<TEntity> SearchFor(Expression<Func<TEntity, bool>> filter);
TEntity GetById(int id);
void Insert(TEntity entity);
void Delete(TEntity entity);
void Update(TEntity entity);
}
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity: class
{
private DbSet<TEntity> _dbSet; // put the entity specified in place of TEntity in d DbSet so i can query the entity e.g School Entity
private NaijaSchoolsContext _naijaSchoolsContext;
public GenericRepository(NaijaSchoolsContext context)
{
_naijaSchoolsContext = context;
_dbSet = _naijaSchoolsContext.Set<TEntity>(); //return the entity specified in the TEntity and put it in DbSet
}
public IEnumerable<TEntity> SearchFor(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter)
{
return _dbSet.Where(filter);
}
public TEntity GetById(int id)
{
return _dbSet.Find(id);
}
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
}
public void Delete(TEntity entity)
{
_dbSet.Remove(entity);
}
public void Update(TEntity entity)
{
_dbSet.AddOrUpdate(entity);
}
}
I also have a UoW like this:
public interface IUnitofWork : IDisposable
{
void Save();
}
public class UnitofWork : IUnitofWork
{
NaijaSchoolsContext naijaSchoolsContext = new NaijaSchoolsContext();
private GenericRepository<School> schoolRepository;
private bool isDisposed = false;
public GenericRepository<School> SchoolRepository
{
get
{
if (schoolRepository == null)
{
schoolRepository = new GenericRepository<School>(naijaSchoolsContext);
}
return schoolRepository;
}
}
public void Save()
{
naijaSchoolsContext.SaveChanges();
}
public void Dispose(bool disposing)
{
if (!isDisposed)
{
if (disposing)
{
naijaSchoolsContext.Dispose();
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
My test class looks like this:
[TestFixture]
public class when_working_with_school_repository
{
}
public class and_saving_a_school : when_working_with_school_repository
{
private School _returnedSchool;
private School _school;
private Mock<IRepository<School>> _repository;
private Exception _result;
[SetUp]
private void SetUp()
{
_repository = new Mock<IRepository<School>>();
_school = new School();
}
[Test]
public void then_a_valid_school_should_be_saved()
{
_repository.Setup(s => s.Insert(_school));
//_returnedSchool = _schoolRepository.Save(_school);
}
[Test]
public void should_throw_an_exception_when_no_school_is_saved()
{
try
{
_repository.Setup(s => s.Insert(null));
}
catch (Exception exception)
{
_result = exception;
}
}
[Test]
public void should_notify_user_if_school_name_already_exists()
{
//bool exists = _schoolRepository.IsExist(_school.Name);
}
}
My tests passes but my concern is that
Am I not supposed to mock the UnitOfWork class. When I tried mocking it, i couldn't get to the StudentRepository class. In using the code without tests, I would have to instantiate UoW to perform my actions, that is why i asked if am supposed to Mock my UoW. if am to Mock it how can i do that?
Please help me if my test is correct or I need to take another course of action.
No, you are not. You are testing mock:
_repository = new Mock<IRepository<School>>();
You want to test your code, not others. Your generic repository simply delegates calls to _dbSet. And that's what you want to test - that calls are delegated (this is sort of wrapper-functionality).
How to do that? You need abstraction over DbSet<T> and this is the object you mock in test. All your tests will look similar:
var dbSetMock = new Mock<DbSet<School>>();
var context = new Mock<Context>();
var repository = new GenericRepository<School>(dbSetMock, context);
repository.FindBy(arg);
dbSetMock.Verify(d => d.FindBy(arg));
This requires abstraction over both DbSet and your custom context to make it work.
I think you're better of mocking the IRepository. But, your test will pass because your not asserting for anything.
I think you need to setup your your mock inorder to get the desired result. Here is a modified example:
[Test]
public void then_a_valid_school_should_be_saved()
{
var _school = new School { .... };
var expected = _school.Id;
_repository.Setup(s => s.Insert(_school));
_repository.Setup(s => s.GetById(_school.Id)).Returns(_school);;
_repository.Insert(_school);
var actual = _repository.GetById(_school.Id);
Assert.Equal(expected, actual);
}
That should do it. To make the test fail try putting a different Id for the expected result and verify that it works. You can use that to improve upon your other test.
Hi I am using Unity to manage my service layers, which in turn speak to UnitOfWork which manages all the repositories.
Some of my services call other services, my question is how can i pass the same UnitOfWork between service layers?
In my case all controller actions are initiated from a GUI on each button action or event on a timer, this is why I have a factory to create UnitOfWork on demand, but it is causing issues as i dont know how to pass this UnitOfWork between services.
Especially difficult is knowing how to get this specific UnitOfWork instance injected into the service constructor. Please note that some of the services may be long running (10 minutes or so on a background thread), i don't know if that has any impact on the design or not.
Currently the service that is called from the other service is then creating its own UnitOfWork which is causing issues for both transactional design, and Entity framework entity tracking.
Suggestions very welcome!
class OtherService : IOtherService
{
public OtherService(IUnitOfWorkFactory unitOfworkFactory,
ISettingsService settingsService)
{
UnitOfWorkFactory = unitOfworkFactory;
SettingsService = settingsService;
}
IUnitOfWorkFactory UnitOfWorkFactory;
ISettingsService SettingsService;
function SomeSeviceCall()
{
// Perhaps one way is to use a factory to instantiate a
// SettingService, and pass in the UnitOfWork here?
// Ideally it would be nice for Unity to handle all of
// the details regardless of a service being called from
// another service or called directly from a controller
// ISettingsService settingsService =
// UnityContainer.Resolve<ISettingService>();
using (var uow = UnitOfWorkFactory.CreateUnitOfWork())
{
var companies = uow.CompaniesRepository.GetAll();
foreach(Company company in companies)
{
settingsService.SaveSettings(company, "value");
company.Processed = DateTime.UtcNow();
}
uow.Save();
}
}
}
class SettingsService : ISettingsService
{
public SettingsService(IUnitOfWorkFactory unitOfworkFactory)
{
UnitOfWorkFactory = unitOfworkFactory;
}
IUnitOfWorkFactory UnitOfWorkFactory;
// ISettingsService.SaveSettings code in another module...
function void ISettingsService.SaveSettings(Company company,
string value)
{
// this is causing an issue as it essentially creates a
// sub-transaction with the new UnitOfWork creating a new
// Entiy Framework context
using (var uow = UnitOfWorkFactory.CreateUnitOfWork())
{
Setting setting = new Setting();
setting.CompanyID = company.CompanyID;
setting.SettingValue = value;
uow.Insert(setting);
uow.Save();
}
}
}
Hi I've been battling with this problem this is what I've come up with...
public class UnitOfWorkFactory
{
private static readonly Hashtable _threads = new Hashtable();
private const string HTTPCONTEXTKEY =
"AboutDbContext.UnitOfWorkFactory";
public static IUnitOfWork Create()
{
IUnitOfWork unitOfWork = GetUnitOfWork();
if (unitOfWork == null || unitOfWork.IsDisposed)
{
unitOfWork = new UnitOfWork();
SaveUnitOfWork(unitOfWork);
}
return unitOfWork;
}
public static IUnitOfWork GetUnitOfWork()
{
if (HttpContext.Current != null)
{
if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
{
return (IUnitOfWork)HttpContext
.Current.Items[HTTPCONTEXTKEY];
}
return null;
}
var thread = Thread.CurrentThread;
if (string.IsNullOrEmpty(thread.Name))
{
thread.Name = Guid.NewGuid().ToString();
return null;
}
lock (_threads.SyncRoot)
{
return (IUnitOfWork)_threads[Thread.CurrentThread.Name];
}
}
private static void SaveUnitOfWork(IUnitOfWork unitOfWork)
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork;
}
else
{
lock (_threads.SyncRoot)
{
_threads[Thread.CurrentThread.Name] = unitOfWork;
}
}
}
public static void DisposeUnitOfWork(IUnitOfWork unitOfWork)
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items.Remove(HTTPCONTEXTKEY);
}
else
{
lock (_threads.SyncRoot)
{
_threads.Remove(Thread.CurrentThread.Name);
}
}
}
}
public interface IUnitOfWork : IDisposable
{
void Commit();
bool IsDisposed { get; }
}
public class UnitOfWork : MyContext
{
}
public abstract class Repository<T>
: IRepository<T>, IDisposable where T : class
{
private UnitOfWork _context;
private UnitOfWork Context
{
get
{
if (_context == null || _context.IsDisposed)
return _context = GetCurrentUnitOfWork<UnitOfWork>();
return _context;
}
}
public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>()
where TUnitOfWork : IUnitOfWork
{
return (TUnitOfWork)UnitOfWorkFactory.GetUnitOfWork();
}
public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate).ToList();
}
public bool Exists(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Any(predicate);
}
public T First(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate).FirstOrDefault();
}
public IEnumerable<T> GetAll()
{
return Context.Set<T>().ToList();
}
public IEnumerable<T> GetAllOrderBy(Func<T, object> keySelector)
{
return Context.Set<T>().OrderBy(keySelector).ToList();
}
public IEnumerable<T> GetAllOrderByDescending(Func<T, object> keySelector)
{
return Context.Set<T>().OrderByDescending(keySelector).ToList();
}
public void Commit()
{
Context.SaveChanges();
}
public void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public void Update(T entity)
{
Context.Entry(entity).State = EntityState.Modified;
}
public void Delete(T entity)
{
Context.Set<T>().Remove(entity);
}
public void Dispose()
{
if (Context != null)
{
Context.Dispose();
}
GC.SuppressFinalize(this);
}
}
public class MyContext : DbContext, IUnitOfWork
{
public DbSet<Car> Cars { get; set; }
public void Commit()
{
SaveChanges();
}
protected override void Dispose(bool disposing)
{
IsDisposed = true;
UnitOfWorkFactory.DisposeUnitOfWork(this);
base.Dispose(disposing);
}
public bool IsDisposed { get; private set; }
}
Then I can do:
using (var unitOfWork = UnitOfWorkFactory.Create())
{
_carRepository.Add(new Car
{
Make = "Porshe", Name = "Boxter"
});
_carRepository.Commit();
}
You could use some kind of "current" unit of work which is tied to current thread and explicitly resolved in service code. You need class to hold thread static instance of UoW to achieve this. However, this is not very good solution.
You be the judge...
I think you are double doing it.
Point 1:
http://www.britannica.com/topic/Occams-razor
Point 2:
From the F2 object browser description of EF main object, the DBContext...
public class DbContext
Member of System.Data.Entity
Summary:
A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that it can be used to query from a database and group together changes that will then be written back to the store as a unit.