Creating a new MVC project and like the idea of repositories in the data layer, so i have implemented them. I have also created a Service layer to handle all business logic and validation, this layer in turn uses the appropriate repository. Something like this (I am using Simple Injector to inject)
DAL LAYER
public class MyRepository {
private DbContext _context;
public MyRepository(DbContext context) {
_context = context;
}
public MyEntity Get(int id)
{
return _context.Set<MyEntity>().Find(id);
}
public TEntity Add(MyEntity t)
{
_context.Set<MyEntity>().Add(t);
_context.SaveChanges();
return t;
}
public TEntity Update(MyEntity updated, int key)
{
if (updated == null)
return null;
MyEntity existing = _context.Set<MyEntity>().Find(key);
if (existing != null)
{
_context.Entry(existing).CurrentValues.SetValues(updated);
_context.SaveChanges();
}
return existing;
}
public void Delete(MyEntity t)
{
_context.Set<MyEntity>().Remove(t);
_context.SaveChanges();
}
}
SERVICE LAYER
public class MyService {
private MyRepository _repository;
public MyService(MyRepository repository) {
_repository = repository;
}
public MyEntity Get(int id)
{
return _repository.Get(id);
}
public MyEntity Add(MyEntity t)
{
_repository.Add(t);
return t;
}
public MyEntity Update(MyEntity updated)
{
return _repository.Update(updated, updated.Id);
}
public void Delete(MyEntity t)
{
_repository.Delete(t);
}
}
Now this is very simple, so i can use the following code to update an object.
MyEntity entity = MyService.Get(123);
MyEntity.Name = "HELLO WORLD";
entity = MyService.Update(entity);
Or this to create an object
MyEntity entity = new MyEntity();
MyEntity.Name = "HELLO WORLD";
entity = MyService.Add(entity);
// entity.Id is now populated
Now say i needed to update an item based on the creation Id of another, i could use the code above all fine, but what happens if an error occurs? I need some sort of transaction/rollback. Is this what the Unit Of Work pattern is suppose to solve?
So i guess i need to have DbContext in my UnitOfWork object, so i create an object like so?
public class UnitOfWork : IDisposable {
private DbContext _context;
public UnitOfWork(DbContext context) {
_context = context;
}
public Commit() {
_context.SaveChanges();
}
public Dispose() {
_context.Dispose();
}
}
Ok so again, thats quite simple. UnitOfWork holds the context as well ( i use same context on all repositories anyway) and it calls the SaveChanges() method. I would then remove the SaveChanges() method call from my repository. So to add i would do the following:
UnitOfWork uow = new UnitOfWork(new DbContext()); // i would inject this somehow
MyEntity entity = new MyEntity();
MyEntity.Name = "HELLO WORLD";
entity = MyService.Add(entity);
uow.Commit();
But what if i need to create an object and then update other objects based on that Id, this will now not work, because the Id will not be created until i call Commit on the uow. Example
UnitOfWork uow = new UnitOfWork(new DbContext()); // i would inject this somehow
MyEntity entity = new MyEntity();
MyEntity.Name = "HELLO WORLD";
entity = MyService.Add(entity);
// entity.Id is NOT populated
MyEntity otherEntity = MyService.Get(123);
otherEntity.OtherProperty = entity.Id;
MyService.Update(otherEntity);
uow.Commit(); // otherEntity.OtherProperty is not linked.....?
So i have a feeling that this UnitOfWork class is not right... maybe i am miss understanding something.
I need to be able to add an entity and get that Id and use it on another entity, but if an error occurs, i want to "rollback" like an ado.net transaction would do.
Is this functionality possible using Entity Framework and Repositories?
See Question&Answers more detail:
os