Шаблон Репозиторий / Единица работы - Как запросить в репозитории объекты, отвечающие определенным критериям? - PullRequest
5 голосов
/ 14 мая 2011

У меня есть стандартный интерфейс репозитория в C #, который включает следующие методы:

IEnumerable<T> GetAll();
T GetById(int id);
void Delete(T entity);
void Add(T entity);

На моем доменном уровне все, что я создаю, это новая оболочка Unit of Work и передача ее в хранилище.Класс оболочки Unit of Work скрывает, использую ли я NHibernate или Entity Framework, и предоставляет метод Commit ().

Как в моем доменном слое, как я могу запрашивать объекты, которые соответствуют только определенным критериям?

Я думаю, что то, что я делаю сейчас, ужасно неэффективно.В настоящее время я делаю это:

var results = myRepository.GetAll().Where......

Если у меня очень большое количество объектов, собирается ли GetAll () возвращать каждый из них, прежде чем отфильтровать те, которые мне не нужны?Как я могу вообще предотвратить возвращение нежелательного объекта?

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

т.е. - я не думаю, что я должен добавлять такие вещи, как (но, возможно, я ошибаюсь):

IList<T> GetAllWhereMeetsMyCriteria();

Ответы [ 3 ]

6 голосов
/ 14 мая 2011

Да, ваш GetAll().Where будет тянуть все ваши объекты из базы данных в ваше приложение и выполнять linq-to-objects.Решение @Kamyar сделает то же самое.@Dysaster предоставил правильное решение, когда я писал этот ответ.

Прежде всего - вам действительно нужен репозиторий, который должен поддерживать как NHibernate, так и EF?Это требование клиента?Если не вы тратите ресурсы.Выберите технологию и создайте минимальную абстракцию, необходимую для того, чтобы ваше приложение следовало разделению интересов.

Если вам действительно требуется высокий уровень абстракции и абсолютная независимость от API персистентности, следует использовать третий шаблон из семейства - Спецификациярисунок .С помощью пользовательских спецификаций вы сможете изменить постоянство на что угодно, если вы переведете условия, описанные в спецификации, в действия, необходимые для источника данных.Критерии API в NHibernate или методы расширения в IQueryable являются спецификациями, но они зависят от технологии.

3 голосов
/ 14 мая 2011

Взгляните на шаблон репозитория, используемый в этом сообщении в блоге [weblogs.asp.net].Я нашел в исходном коде несколько интересных шаблонов, к которым я продолжаю возвращаться и проверять снова.Код реализует шаблоны хранилища и единицы работы.

Чтобы ответить на ваш конкретный вопрос, интерфейс хранилища содержит метод:

IEnumerable<T> GetMany(Expression<Func<T, bool>> where);    

Он реализован следующим образом в классе RepositoryBase<T>:

public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
    return dbset.Where(where).ToList();
}

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

2 голосов
/ 14 мая 2011

Не знаком с nhibernate, но обычно я иду с вашим последним решением (IList<T> GetAllWhereMeetsMyCriteria();):

public IList<TEntity> Find<TEntity>(Func<TEntity, bool> criteria) where TEntity : class
{
    return this.Query<TEntity>().Where<TEntity>(criteria).ToList<TEntity>();
}  

Существует большое хранилище Genric, написанное по адресу: http://www.martinwilley.com/net/code/nhibernate/genericrepository.html

Возможно, вы захотите использовать это, поскольку оно охватывает больше ситуаций. Кроме того, вы можете извлечь свой собственный репозиторий из него для определенных нужд. (Пример: http://www.martinwilley.com/net/code/nhibernate/productrepository.html)

UPDATE
Вы можете определить пользовательские критерии в своих производных репозиториях и использовать их. например

private ICriteria CriteriaCategoryId(int categoryId)
    {
        ICriteria criteria = Session.CreateCriteria(typeof(Product));
        criteria.CreateCriteria("Category")
            .Add(Expression.Eq("Id", categoryId));
        return criteria;
    }  
public IList<Product> ProductByCategory(int categoryId, int pageStartRow, int pageSize)
    {
        var criteria = CriteriaCategoryId(categoryId)
            .SetFirstResult(pageStartRow)
            .SetMaxResults(pageSize);

        return criteria.List<Product>();
    }
...