Estrutura de Entidades 6 e Unidade de Trabalho ... Onde, Quando? É como transações no ado.net?
Criando um novo projeto MVC e gosto da ideia de repositórios na camada de dados, então eu os implementei. Eu também criei uma camada de Serviço para lidar com toda a lógica e validação de negócios. Essa camada, por sua vez, usa o repositório apropriado. Algo assim (estou usando o Simple Injector para injetar)
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();
}
}
CAMADA DE SERVIÇO
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);
}
}
Agora isso é muito simples, então eu posso usar o código a seguir para atualizar um objeto.
MyEntity entity = MyService.Get(123);
MyEntity.Name = "HELLO WORLD";
entity = MyService.Update(entity);
Ou isso para criar um objeto
MyEntity entity = new MyEntity();
MyEntity.Name = "HELLO WORLD";
entity = MyService.Add(entity);
// entity.Id is now populated
Agora diga que eu precisava atualizar um item com base no ID de criação de outro, eu poderia usar o código acima de tudo bem, mas o que acontece se ocorrer um erro? Eu preciso de algum tipo de transação / reversão. É isso que o padrão da Unidade de Trabalho deve resolver?
Então, eu acho que preciso ter DbContext no meu objeto UnitOfWork, para criar um objeto como esse?
public class UnitOfWork : IDisposable {
private DbContext _context;
public UnitOfWork(DbContext context) {
_context = context;
}
public Commit() {
_context.SaveChanges();
}
public Dispose() {
_context.Dispose();
}
}
Ok, novamente, isso é bastante simples. UnitOfWork também mantém o contexto (eu uso o mesmo contexto em todos os repositórios) e chama o método SaveChanges (). Eu removeria a chamada do método SaveChanges () do meu repositório. Então, para adicionar, eu faria o seguinte:
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();
Mas e se eu precisar criar um objeto e depois atualizar outros objetos com base nesse ID, isso agora não funcionará, porque o ID não será criado até que eu chame Commit no uow. Exemplo
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.....?
Então, eu tenho a sensação de que essa classe UnitOfWork não está certa ... talvez eu sinta falta de entender algo.
Eu preciso ser capaz de adicionar uma entidade e obter esse ID e usá-lo em outra entidade, mas se ocorrer um erro, eu quero "reverter" como faria uma transação ado.net.
Essa funcionalidade é possível usando o Entity Framework and Repositories?