Architektura cebuli, jednostka pracy i ogólny wzór repozytorium

Po raz pierwszy wdrażam podejście projektowe oparte na domenie. Postanowiłem spróbowaćArchitektura cebuli ponieważ koncentruje się na domenie, a nie na infrastrukturze / platformach / itp.

Aby oderwać się od Entity Framework, stworzyłemogólne repozytorium zJednostka pracy realizacja.

TheIRepository<T> iIUnitOfWork interfejsy:

public interface IRepository<T>
{
    void Add(T item);

    void Remove(T item);

    IQueryable<T> Query();
}

public interface IUnitOfWork : IDisposable
{
    void SaveChanges();
}

Implementacje Framework EntityIRepository<T> iIUnitOfWork:

public class EntityFrameworkRepository<T> : IRepository<T> where T : class
{
    private readonly DbSet<T> dbSet;

    public EntityFrameworkRepository(IUnitOfWork unitOfWork)
    {
        var entityFrameworkUnitOfWork = unitOfWork as EntityFrameworkUnitOfWork;

        if (entityFrameworkUnitOfWork == null)
        {
            throw new ArgumentOutOfRangeException("Must be of type EntityFrameworkUnitOfWork");
        }

        dbSet = entityFrameworkUnitOfWork.GetDbSet<T>();
    }

    public void Add(T item)
    {
        dbSet.Add(item);
    }

    public void Remove(T item)
    {
        dbSet.Remove(item);
    }

    public IQueryable<T> Query()
    {
        return dbSet;
    }
}

public class EntityFrameworkUnitOfWork : IUnitOfWork
{
    private readonly DbContext context;

    public EntityFrameworkUnitOfWork()
    {
        this.context = new CustomerContext();;
    }

    internal DbSet<T> GetDbSet<T>()
        where T : class
    {
        return context.Set<T>();
    }

    public void SaveChanges()
    {
        context.SaveChanges();
    }

    public void Dispose()
    {
        context.Dispose();
    }
}

TheKlient magazyn:

public interface ICustomerRepository : IRepository<Customer>
{

}

public class CustomerRepository : EntityFrameworkRepository<Customer>, ICustomerRepository 
{
    public CustomerRepository(IUnitOfWork unitOfWork): base(unitOfWork)
    {
    }
}

Kontroler ASP.NET MVC korzystający z repozytorium:

public class CustomerController : Controller
{
    UnityContainer container = new UnityContainer();

    public ActionResult List()
    {
        var unitOfWork = container.Resolve<IUnitOfWork>();
        var customerRepository = container.Resolve<ICustomerRepository>();

        return View(customerRepository.Query());
    }

    [HttpPost]
    public ActionResult Create(Customer customer)
    {
        var unitOfWork = container.Resolve<IUnitOfWork>();
        var customerRepository = container.Resolve<ICustomerRepository>();; 

        customerRepository.Add(customer);

        unitOfWork.SaveChanges();

        return RedirectToAction("List");
    }
}

Zastrzyk zależności z jednością:

container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>();
container.RegisterType<ICustomerRepository, CustomerRepository>();

Rozwiązanie:

PROBLEMY?

Implementacja repozytorium (kod EF) jest bardzo ogólna. To wszystko siedzi na bokuEntityFrameworkRepository<T> klasa. Konkretne repozytoria modeli nie zawierają żadnej z tych logik. Oszczędza mi to pisania ton nadmiarowego kodu, ale może poświęcić elastyczność?

TheICustomerRepository iCustomerRepository klasy są zasadniczo puste. Są wyłącznie po to, by zapewnić abstrakcję. O ile rozumiem, pasuje to do wizji architektury Onion, w której infrastruktura i kod zależny od platformy znajdują się na zewnątrz systemu, ale posiadanie pustych klas i pustych interfejsów jest błędne?

Aby użyć innej implementacji trwałości (powiedzmy Azure Table Storage), to nowaCustomerRepository klasa musiałaby zostać utworzona i dziedziczyćAzureTableStorageRepository<T>. Ale może to prowadzić do nadmiarowego kodu (wiele CustomerRepositories)? Jak ten efekt drwił?

Inna implementacja (powiedzmy Azure Table Storage) ma ograniczenia w obsłudze międzynarodowej, więc klasa AzureTableStorageUnitOfWork nie będzie działać w tym kontekście.

Czy są jakieś inne problemy ze sposobem, w jaki to zrobiłem?

(Większość inspiracji czerpałem zten post)

questionAnswers(3)

yourAnswerToTheQuestion