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

C# 有没有办法在没有数据源的情况下创建一个LINQ查询作为变量?,c#,asp.net,linq,entity-framework-4,linq-to-entities,C#,Asp.net,Linq,Entity Framework 4,Linq To Entities,序言: 我的核心问题与此非常相似:至今仍未得到回答。我希望如果我用不同的方式来处理这个问题,问一个稍微不同的问题,我可能会得到一个结果。我将重复另一个问题中的一些内容,以避免要求读者根据上下文阅读 问题: 我正在使用POCO实体和实体框架4。我尝试在应用层对实体集进行复杂的即席过滤,同时尝试避免将IQueryable暴露在存储库边界之外。这给我留下了一些麻烦 我不想在存储库上创建一个需要大量参数列表的单一大规模筛选方法,例如: IEnumerable GetFilteredCustomers(

序言:
我的核心问题与此非常相似:至今仍未得到回答。我希望如果我用不同的方式来处理这个问题,问一个稍微不同的问题,我可能会得到一个结果。我将重复另一个问题中的一些内容,以避免要求读者根据上下文阅读

问题:
我正在使用POCO实体和实体框架4。我尝试在应用层对实体集进行复杂的即席过滤,同时尝试避免将
IQueryable
暴露在存储库边界之外。这给我留下了一些麻烦

  • 我不想在存储库上创建一个需要大量参数列表的单一大规模筛选方法,例如:

    IEnumerable GetFilteredCustomers(string nameFilter, string addressFilter, bool isActive, int customerId, ...)
    
    这不仅是非常麻烦的使用,但它的超级丑陋的看,尤其是如果它主要是一堆空,等等。它也不是像我想维护

  • 我不想在存储库中创建大量的筛选方法,例如:

    IEnumerable GetActiveCustomers()
    IEnumerable GetCustomersByName()
    
    这种方法有很多问题,包括需要大量的方法列表,这些方法会增长到
    n其中n是可用筛选条件的数量,如果我希望能够以任意方式组合它们。(即所有名为George的活跃客户)。也很难维护。
    

  • 我不想创建可链接的方法(Fluent接口)来操作
    IEnumerable
    ,因为最终这涉及从数据库中带回一个巨大的结果集,并将其过滤到内存中,这不是一个可伸缩的解决方案

  • 我无法创建一个流畅的界面来操作
    IQueryable
    ,因为正如我已经说过的,我不想将
    IQueryable
    暴露在存储库之外

  • 我希望通过传递一个充满参数的对象而不是一个大的参数列表来避免简单地重新设置单个大规模过滤器方法,尽管在这一点上这可能是最不丑陋的解决方案

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

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

从另一个角度来看,考虑以下内容:

IQueryable<Customer> filteredCustomers = customerRepository.GetAll()
    .Where(c => c.FirstName == "Dave")
    .Where(c => c.IsActive == true)
    .Where(c => c.HasAddress == true)
    ;
IQueryable filteredCustomers=customerRepository.GetAll()
.其中(c=>c.FirstName==“Dave”)
.其中(c=>c.IsActive==true)
.Where(c=>c.HasAddress==true)
;

我想将这三个Where子句打包为一个查询对象,完全独立于customerRepository.GetAll(),将其作为参数传递,稍后再应用。

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

public Expression<Func<Customer, bool>> GetDave()
{
    return c => c.FirstName == "Dave"
             && c.IsActive
             && c.HasAddress;
}

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

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

我想你可能有点越界了,把事情搞得太复杂了。您是在做重构练习还是从头开始?您反对直接使用Linq表达式树吗?那么,“使用原始LINQ查询,但以某种方式将其存储在变量中,然后将其应用于数据源”的问题是什么?使用LINQ表达式:我建议公开IQueryable。如果没有,人们无论如何都会尝试使用linq,他们将停止使用linq来处理对象,性能将非常糟糕。从他的问题:“我无法创建一个流畅的界面来操作
IQueryable
,因为正如我已经说过的,我不想将
IQueryable
暴露在存储库之外。这看起来很有希望。根据你的例子,我已经建立了一个简单的版本,它完成了基本的工作。。。但是:有什么方法可以组合表达式吗?我希望有一个表达式用于名称比较,一个用于IsActive,一个用于HasAddress,然后任意组合它们。。。否则,我仍然陷于这样一种境地:我必须为我想做的每一种可能的过滤组合构造一个表达式。。。但至少现在我可以在应用程序级别构建这些表达式,并且仍然传回IEnumerable或ListCombining表达式,这比您预期的要困难得多,但是LINQPad的LINQKit库减轻了很多痛苦。看起来我可以在对象中构建一个存储表达式列表(而不是“连接”它们)的接口,然后在存储库中按顺序应用每个表达式。@Mir只要你想“和”表达式,它就可以正常工作。如果你想“或”他们(或做更复杂的事情),你可能需要LINQKit。
var dave = Repository.GetOneGuy(this.GetDave()).Single();
public static class ExtnensionsForIQueryableCustomer
{
    public static IEnumerable<Customer> WhereActiveWithAddressAndNamed (this IQueryable<Customer> queryable, string name)
    {
        return queryable.Where (c => c.FirstName == name)
                        .Where (c => c.IsActive)
                        .Where (c => c.HasAddress);
    }
}
customerRepository.GetAll ().WhereActiveWithAddressAndNamed ("Dave");