UnitOfWork — Репозиторий — Рекомендации по шаблону обслуживания

Поэтому обычно при реализации этого шаблона я Service беру Repository<Type>, а затем репозиторий берет UnitOfWork.

Я играл с подвешиванием метода к UnitOfWork, который получает Repository<Type> вот так:

public class UnitOfWork : IUnitOfWork
{
    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : Core.Domain.Model.EntityBase<TEntity>
    {
        return new Repository<TEntity>(this);
    }
}

Затем Service возьмет UnitOfWork и сможет разрешить необходимые репозитории из него.

Что вы думаете? Вы видите какие-то недостатки в этом?


person Sam    schedule 10.02.2013    source источник
comment
Общие репозитории на самом деле не служат никакой цели, если вы используете OR/M.   -  person jgauffin    schedule 12.02.2013
comment
@jgauffin - Не могли бы вы немного рассказать об этом для меня, пожалуйста?   -  person Sam    schedule 14.02.2013
comment
Универсальные репозитории не дают никаких преимуществ по сравнению с прямым использованием OR/M, если только вы не настроите их для каждого типа сущности.   -  person jgauffin    schedule 14.02.2013


Ответы (1)


Я использую аналогичный подход в своей программе ASP.NET MVC, и пока он работает очень хорошо.

Мой IUnitOfWork интерфейс выглядит так:

public interface IUnitOfWork
{
    IRepository<TEntity> GetRepositoryFor<TEntity>() where TEntity : class;
    void SaveChanges();
}

и связанный интерфейс IRepository выглядит так:

public interface IRepository<TEntity> : IQueryable<TEntity> where TEntity : class
{
    TEntity Find(params object[] keyValues);

    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

А затем передайте его моему сервису так:

public abstract class BaseService
{
    public BaseService(IUnitOfWork unitOfWork)
    {
        // etc...
    }
}

Вы правы в том, что это позволяет службе легко разрешать свои репозитории без необходимости передавать их в конструктор по отдельности, что полезно в случаях, когда вы можете работать с несколькими репозиториями в одной службе (например, заказы на покупку и продукты).

Одним из преимуществ использования таких интерфейсов, не зависящих от ORM, является то, что это означает, что вы можете легко переключаться между ORM. Я буду честен, шансы на то, что я перейду с Entity Framework на другую ORM, невелики, но факт в том, что я мог бы, если возникнет необходимость. В качестве бонуса мои сервисы намного проще тестировать, и я также считаю, что это делает мой класс сервиса чище, поскольку теперь он совершенно не знает об используемом ORM и работает полностью против двух интерфейсов выше.

Что касается комментариев об универсальном интерфейсе репозитория, мой совет — быть прагматичным и делать то, что лучше всего подходит для вас и вашего приложения. В Stackoverflow есть ряд вопросов по этой самой теме, и ответы на них сильно различаются в зависимости от того, какой путь лучше выбрать (например, разоблачение IQueryable против IEnumerable, общий против не общего).

Я играл с отсутствием универсального репозитория, поскольку вы, возможно, уже заметили, что мой интерфейс IRepository выглядит как IDbSet; Причина, по которой я выбрал этот метод, заключается в том, что он позволяет моей реализации обрабатывать все элементы управления состоянием сущностей Entity Framework, которые вы делаете с DbContext E.G.

public void Delete(TEntity entity)
{
    if (Context.Entry(entity).State == EntityState.Detached)
    {
        EntitySet.Attach(entity);
    }
    EntitySet.Remove(entity);
}

Если бы я использовал IDbSet, мне нужно было бы выполнить это на моем сервисном уровне, что потребовало бы зависимости от DbContext, которая казалась гораздо более дырявой абстракцией, чем мой общий репозиторий.

person Benjamin Gale    schedule 24.04.2013