Ответ 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.