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?

questionAnswers(1)

yourAnswerToTheQuestion