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

Репозиторий/объект IQueryable/Query Object

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

1) Первый заключается в том, что разные поставщики LINQ могут вести себя по-разному, и эта разница должна содержаться в репозитории.

2) Во-вторых, чтобы разработчики уровня сервиса не модифицировали запрос базы данных, чтобы он случайно вызывал проблемы с производительностью.

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

Проблема 1, похоже, будет решена с использованием шаблона объекта данных.

например. public IEnumerable<T> FindBy(Query query)

Мой вопрос в том, почему бы мне не просто передать выражение лямбда в, поскольку это независимое от поставщика, похоже, предоставит мне те же функции, что и объект запроса, и тот же уровень разделения?

например. public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)

Есть ли причина не делать этого? Разве это нарушает некоторые правила? Best-практика? о чем я должен знать?

4b9b3361

Ответ 1

Просто верните IQueryable<T>.

Прежде чем вы напишете еще один бит "кода репозитория", вы значительно выиграете от чтения статьи Айенде "Архитектура в яме судьбы" - "Зло репозитория" Уровень абстракции

Ваш подход, без сомнения, добавляет значительную ненужную сложность.

Весь код из другого вопроса в Общий список OrderBy Lambda не выполняет ничего, кроме маскировки существующего эффективного API с ненужной и незнакомой абстракцией.

Что касается ваших двух проблем,

  • Поставщики LINQ ведут себя по-разному, но пока предикаты, которые вы передаете, могут обрабатываться поставщиком LINQ, это не имеет значения. В противном случае вы все равно столкнетесь с одной и той же проблемой, потому что вы передаете Expression, который в любом случае будет передан в IQueryable. Если реализация IQueryProvider не может обрабатывать ваш предикат, она не сможет обработать ваш предикат. (Вы всегда можете вызвать ToList(), если вам нужно оценить до дальнейшей фильтрации, которая не может быть переведена).

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

Если вы хотите скрыть свою логику запросов с переднего конца, не пытайтесь создать общий репозиторий. Инкапсулируйте запросы с помощью конкретных бизнес-методов. Теперь, я могу ошибаться, но я предполагаю, что ваше использование шаблона репозитория вдохновлено дизайном Domain Driven. Если это так, то причина использования репозитория заключается в том, чтобы разрешить создание несовместимого с персистентством домена с первичным фокусом на модели домена. Однако использование такого типа общего репозитория не намного больше, чем изменение семантики от Create Read Update Delete до Find Add Remove Save. В нем нет никаких реальных бизнес-знаний.

Рассмотрим значимость (и удобство использования)

interface IPersonRepository 
{ 
     Person GetById(int id);
     IEnumerable<Person> FindByName(string firstName, string lastName);
}

в отличие от

interface IRepository<T> { 
     IEnumerable<T> FindBy(Query<T> query);
}

Кроме того, можете ли вы на самом деле указать на использование IRepository<T> вообще (в отличие от IQueryable<T>)?

Также учтите, что с общим подходом вы на самом деле не инкапсулируете логику запросов. В итоге вы создаете его извне, что приведет к дополнительному ненужному коду.

* Еще одна заметка о ресурсах, которые не рекомендуют использовать IQueryable<T>, заключается в том, что стоит посмотреть дату публикации. Было время, когда доступность LINQ-провайдеров была довольно ограниченной (для ранних EF и LINQ-to-SQL). В то время экспозиция IQueryable<T> повлечет за собой несовместимость с некоторыми из более популярных заменителей Microsoft ORM (LINQ-to-NHibernate уже давно реализована). На данный момент поддержка LINQ практически повсеместна в серьезных библиотеках ORM.NET.