Подтвердить что ты не робот

Лучший способ реализации шаблона репозитория?

Я изучал BDD/DDD и, как следствие, пытался придумать правильную реализацию шаблона репозитория. До сих пор было трудно найти консенсус относительно наилучшего способа реализации этого. Я попытался свести его до следующих вариантов, но я не уверен, что это лучший подход.

Для справки Я создаю приложение ASP.MVC с NHibernate как фоновый.

public interface IRepository<T> {
        // 1) Thin facade over LINQ
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IQueryable<T> Find();
        // or possibly even
        T Get(Expression<Func<T, bool>> query);
        List<T> Find(Expression<Func<T, bool>> query);
}

public interface IRepository<T> {
        // 2) Custom methods for each query
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySku(string sku);
        IList<T> FindByName(string name);
        IList<T> FindByPrice(decimal price);
        // ... and so on
}

public interface IRepository<T> {
        // 3) Wrap NHibernate Criteria in Spec pattern
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}


public interface IRepository<T> {
        // 4) Expose NHibernate Criteria directly
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> Find(ICriteria criteria);
        // .. or possibly
        IList<T> Find(HQL stuff);
}

Мои первоначальные мысли заключаются в том, что

1) отлично с точки зрения эффективности, но я могу столкнуться с проблемами, поскольку ситуация усложняется.

2) кажется очень утомительным и может закончиться очень переполненным классом, но в противном случае предлагает высокую степень разделения между моей логикой домена и уровнем данных, который мне нравится.

3) кажется сложным фронтом и больше работы для написания запросов, но ограничивает перекрестное загрязнение только уровнем Specs.

4) Моя наименее любимая, но, возможно, самая прямая реализация и, возможно, большинство баз данных для сложных запросов, хотя она несет большую ответственность за код вызова.

4b9b3361

Ответ 1

Я думаю, что все они хорошие варианты (за исключением, может быть, 4, если вы не хотите привязывать себя к nhibernate), и вы, кажется, хорошо разбираетесь в плюсах и минусах, чтобы принять решение самостоятельно, исходя из ваших текущих усилий. Не бить себя слишком сильно.

В настоящее время я работаю над смесью от 2 до 3:

public interface IRepository<T> 
{
        ...
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}

public interface ISpecificRepository : IRepository<Specific> 
{
        ...
        IList<Specific> FindBySku(string sku);
        IList<Specific> FindByName(string name);
        IList<Specific> FindByPrice(decimal price);
}

А также базовый класс репозитория (из T).

Ответ 2

Также есть хороший аргумент для подхода "ни к чему из вышеперечисленных".

Проблема с универсальными репозиториями заключается в том, что вы делаете предположение, что все объекты в вашей системе будут поддерживать все четыре операции CRUD: Create, Read, Update, Delete. Но в сложных системах у вас, вероятно, будут объекты, которые поддерживают только некоторые из операций. Например, у вас могут быть объекты, доступные только для чтения, или созданные, но не обновляемые объекты.

Вы можете разбить интерфейс IRepository на небольшие интерфейсы, для чтения, удаления и т.д., но это становится довольно грязным.

Грегори Янг делает хороший аргумент (с точки зрения DDD/программного обеспечения), что каждый репозиторий должен поддерживать только те операции, которые относятся к объекту домена или агрегату, с которым вы работаете. Здесь его статья о общих хранилищах.

И для альтернативного вида см. этот пост в Ayende .

Ответ 3

Одна из вещей, которые мы делаем, состоит в том, что все наши репозитории имеют разные потребности, поэтому мы создаем набор интерфейсов:

public interface IReadOnlyRepository<T,V>
{
   V Find(T);
}

В этом примере только репозиторий только для чтения получает данные из базы данных. Причиной для T, V является то, что V представляет то, что возвращается репозиторием, а T представляет то, что передается, поэтому вы можете сделать что-то вроде этого:

public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer>
{
    public Customer Find(int customerId)
    {
    }

    public Customer Find(string customerName)
    {
    }
}

Я также могу создать отдельные интерфейсы для добавления, обновления и удаления. Таким образом, если мой репозиторий не нуждается в поведении, он просто не реализует интерфейс.

Ответ 4

Я поклонник bif из 1, потому что я могу создавать фильтры и методы расширения подкачки, чем я могу применить к возвращаемым значениям IQueryable < > для метода Find. Я сохраняю методы расширения в слое данных, а затем создаю "на лету" на бизнес-уровне. (Не совсем чистый, по общему признанию.)

Конечно, когда система стабилизируется, у меня есть возможность сделать определенные методы поиска с использованием тех же методов расширения и оптимизировать с помощью Func < > .

Ответ 5

При использовании NH с Linq ваш репозиторий может быть:

session.Linq<Entity>()

Спецификации - это вещи, которые имеют дело с:

IQueryable<Entity>

Вы можете все это сделать, если хотите, но это много мирской работы, чтобы абстрагировать абстракцию.

Простой - это хорошо. Yah, NH делает базы данных, но он предоставляет гораздо больше шаблонов. Наличие помимо DAL зависимости от NH далеко от греха.

Ответ 6

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

Вам нужно создать строгий уровень (например, вам нужно будет заменить NHibernate на Entity Framework в будущем)? Вы хотите написать тест особенно для методов репозитория?

Нет лучшего способа создания репозитория. Существует всего несколько способов, и это определенно зависит от вас, что наиболее удобно для ваших нужд.

Ответ 7

Исключить репозиторий

Соответствующая статья Джимми Богарда из LosTechies

http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx

Кроме того, другая быстрая статья с некоторыми комментариями, предлагающая версию # 2, действительно является шаблоном DOA, а не репозиторием.

http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html