前言:
我的核心问题与这个问题非常相似:如何编写一个干净的仓库而不将IQueryable暴露给我的应用程序的其余部分?,该问题一直未得到回答。我希望通过以不同的方式解决该问题,并提出略有不同的问题,可以得到结果。为了避免读者阅读上下文,我将重复一些来自其他问题的内容。
问题:
我正在使用POCO实体和Entity Framework 4。 我正在尝试在应用程序层允许对实体集进行复杂的即席过滤,同时试图避免将IQueryable<T>
暴露给我的仓库边界以外的部分。 这让我面临了一些麻烦。
I do not want to create a single massive filter method on the repository that takes a huge list of parameters, such as:
IEnumerable GetFilteredCustomers(string nameFilter, string addressFilter, bool isActive, int customerId, ...)
Not only is this extremely cumbersome to use, but it's super ugly to look at, especially if it's mostly a bunch of nulls, etc. It's also not as maintainable as I would like.
I do not want to create a huge set of filter methods on the repository, such as:
IEnumerable GetActiveCustomers() IEnumerable GetCustomersByName()
There are a number of problems with this approach, including needing a huge list of methods which grows to
n!
where n is the number of available filter conditions if I want to be able to combine them in arbitrary ways. (i.e. all active customers with name George). Also highly difficult to maintain.I do not want to create chainable methods (Fluent Interface) that manipulate
IEnumerable<T>
, because ultimately that involves bringing back a huge result set from the database and filtering it down in-memory which is not a scalable solution.I can't create a Fluent Interface that manipulates
IQueryable<T>
because as I've already said, I don't want to expose theIQueryable<T>
past the repositories.I'd like to avoid simply rehashing the single massive filter method by passing in an object full of parameters instead of a large parameter list, although at this point this might be the least ugly solution.
思路:
我认为最理想的解决方案是发现一种方法来创建一个不知道源的完整查询,并将其存储为参数。然后,我可以将其传递到仓库中,在那里已知源,并将查询应用于源并返回结果。
澄清一下;与上面提到的简单创建参数对象相比,我想使用原始的LINQ查询,但以某种方式将它们存储在变量中,并稍后将它们应用于数据源。我怀疑返回类型必须事先知道,但我非常愿意定义它并事先知道。
从另一个角度来看,考虑以下内容:
IQueryable<Customer> filteredCustomers = customerRepository.GetAll()
.Where(c => c.FirstName == "Dave")
.Where(c => c.IsActive == true)
.Where(c => c.HasAddress == true)
;
我希望将三个Where条件封装成一个查询对象,与customerRepository.GetAll()完全分离,将其作为参数传递并稍后应用。