Преамбула:
Мой основной вопрос очень похож на этот: Как я могу написать чистый репозиторий, не подвергая IQueryable остальной части моего приложения? который остался без ответа. Я надеюсь, что если я подойду к проблеме иначе и задам несколько иной вопрос, я могу получить результат. Я повторю часть содержания этого другого вопроса, чтобы читатели не читали его в контексте.
Проблема:
Я работаю с сущностями POCO и Entity Framework 4. Я пытаюсь разрешить сложную специальную фильтрацию наборов сущностей на уровне приложения, одновременно пытаясь избежать раскрытия IQueryable
за пределами моего репозитория. Это оставляет меня с некоторыми осложнениями.
Я не хочу создавать один метод массивной фильтрации в репозитории, который принимает огромный список параметров, например:
IEnumerable GetFilteredCustomers (string nameFilter, string addressFilter, bool isActive, int customerId, ...)
Это не только чрезвычайно громоздко в использовании, но и ужасно некрасиво на вид, особенно если это в основном куча нулей и т. Д. Это также не так удобно в обслуживании, как хотелось бы.
Я не хочу создавать в репозитории огромный набор методов фильтрации, таких как:
IEnumerable GetActiveCustomers ()
IEnumerable GetCustomersByName ()
У этого подхода есть ряд проблем, в том числе необходимость в огромном списке методов, который вырастает до n!
где n - количество доступных условий фильтрации, если я хочу иметь возможность комбинировать их произвольным образом. (т.е. все активные клиенты с именем Джордж). Также очень сложно обслуживать.
Я не хочу создавать объединяемые в цепочки методы (Fluent Interface), которые манипулируют IEnumerable
, потому что в конечном итоге это включает возврат огромного набора результатов из базы данных и его фильтрацию в памяти, что является не масштабируемое решение.
Я не могу создать Fluent Interface, который манипулирует IQueryable
, потому что, как я уже сказал, я не хочу раскрывать прошлое IQueryable
репозитории.
Я бы не хотел просто перефразировать метод единственного массивного фильтра путем передачи объекта, полного параметров, вместо большого списка параметров, хотя на данный момент это может быть наименее уродливым решением.
Идеи:
В конечном счете, я думаю, что идеальным решением было бы найти способ создать полный запрос, который не знает источника, и сохранить его как параметр. Затем я мог бы передать это в репозиторий, где источник известен, и применить запрос к источнику и вернуть результаты.
Чтобы уточнить; в отличие от простого создания объекта параметров, как упомянуто выше, я хотел бы использовать необработанные запросы LINQ, но каким-то образом сохранить их в переменной и применить их к источнику данных позже. Я подозреваю, что тип возвращаемого значения должен быть известен заранее, но меня вполне устраивает определение этого типа и его наличие заранее.
Чтобы посмотреть на это с другой точки зрения, рассмотрите следующее:
IQueryable filteredCustomers = customerRepository.GetAll()
.Where(c => c.FirstName == "Dave")
.Where(c => c.IsActive == true)
.Where(c => c.HasAddress == true)
;
Я хочу упаковать три предложения Where как объект запроса, полностью отделенный от customerRepository.GetAll (), передать его как параметр и применить это позже.