有没有办法在没有数据源的情况下创建LINQ查询作为变量?

前言:
我的核心问题与此非常相似: 如何在不将IQueryable暴露给我的应用程序的其余部分的情况下编写一个干净的存储库? 一直没有答案。 我希望如果我以不同的方式解决问题,并提出一个稍微不同的问题,我可能会得到一个结果。 我将重复这个问题的一些内容,以避免要求读者阅读上下文。

问题:
我正在使用POCO实体和entity framework4.我试图在应用层允许对实体集进行复杂的ad-hoc过滤,同时试图避免将IQueryable暴露在我的存储库边界之外。 这让我有些困难。

  • 我不想在存储库上创建一个带有大量参数的大规模filter方法,例如:

     IEnumerable GetFilteredCustomers(string nameFilter, string addressFilter, bool isActive, int customerId, ...) 

    这不仅非常麻烦,而且看起来非常难看,特别是如果它主要是一堆零点等等。它也不像我想的那样可维护。

  • 我不想在存储库上创建大量的过滤方法,例如:

     IEnumerable GetActiveCustomers() IEnumerable GetCustomersByName() 

    这种方法存在许多问题,包括需要大量增加到n!的方法n! 其中n是可用过滤条件的数量,如果我希望能够以任意方式组合它们。 (即所有名为George的活跃客户)。 也很难维护。

  • 我不想创建操纵IEnumerable可链接方法(Fluent Interface),因为最终需要从数据库中恢复一个巨大的结果集并将其过滤到内存中,这不是一个可扩展的解决方案。

  • 我无法创建一个操作IQueryable的Fluent接口,因为正如我已经说过的,我不希望将IQueryable暴露在存储库之外。

  • 我想避免简单地通过传入一个充满参数而不是大参数列表的对象来重复单个大规模过滤方法,尽管此时这可能是最难看的解决方案。

思路:
最终,我认为一个理想的解决方案是发现一些方法来创建一个不知道源的完整查询,并将其存储为参数。 然后,我可以将其传递到已知源的存储库中,并将查询应用于源并返回结果。

澄清; 与上面提到的简单地创建参数对象相比,我想使用原始LINQ查询,但以某种方式将它们存储在变量中,并稍后将它们应用于数据源。 我怀疑返回类型必须提前知道,但我完全可以定义并事先知道它。

要从另一个角度查看它,请考虑以下事项:

 IQueryable filteredCustomers = customerRepository.GetAll() .Where(c => c.FirstName == "Dave") .Where(c => c.IsActive == true) .Where(c => c.HasAddress == true) ; 

我想将三个Where子句打包为一个查询对象,与customerRepository.GetAll()完全分开,将其作为参数传递并稍后应用。

当然。 您可以编写如下方法:

 public Expression> GetDave() { return c => c.FirstName == "Dave" && c.IsActive && c.HasAddress; } 

…和存储库方法如:

 public IEnumerable GetOneGuy(Expression> criteria) { return Context.Customers.Where(criteria); } 

…并致电:

 var dave = Repository.GetOneGuy(this.GetDave()).Single(); 

如果您只想以可重用的方式捕获这些类型的查询,可以在IQueryable (或任何您想要的POCO)上将其实现为扩展方法。 就像是:

 public static class ExtnensionsForIQueryableCustomer { public static IEnumerable WhereActiveWithAddressAndNamed (this IQueryable queryable, string name) { return queryable.Where (c => c.FirstName == name) .Where (c => c.IsActive) .Where (c => c.HasAddress); } } 

然后你可以像这样使用它:

 customerRepository.GetAll ().WhereActiveWithAddressAndNamed ("Dave");