使用Predicate <t>手动构建查询有什么好处吗?

时间:2015-09-02 14:03:33

标签: c# linq predicate

假设我想根据用户提取的某些条件过滤客户列表。例如,假设他们可以将文本输入到多个文本框中的任何一个文本框中,并搜索该文本(例如,按客户名称,国家/地区等进行搜索)。

我可以做类似以下的事情......

IEnumerable<Customer> matches = customers; // start off with the full list

if (!string.IsNullOrWhiteSpace(customerName)) {
  matches = matches.Where(c => c.Name.Contains(customerName));
}

if (!string.IsNullOrWhiteSpace(customerCountry)) {
    matches = matches.Where(c => c.Country.Contains(customerCountry));
}

这样做,并且非常易读。

另一方面,我可以做以下事情......

List<Predicate<Customer>> predicates = new List<Predicate<Customer>>{
  c => string.IsNullOrWhiteSpace(customerName) || c.Name.Contains(customerName),
  c => string.IsNullOrWhiteSpace(customerCountry) || c.Country.Contains(customerCountry)
};

IEnumerable<Customer> matches = numbers.Where(n => predicates.All(p => p(n)))

如其中一个答案中所述,上述代码在每种情况下都冗余地检查string.IsNullOrWhiteSpace(customerName)。请忽略这一点,而不是花时间重写代码以解决副作用问题。

一个人对另一个人有什么好处吗?如果没有,我何时会使用谓词?

3 个答案:

答案 0 :(得分:1)

至少,这一个:

c => string.IsNullOrWhiteSpace(customerName) || c.Name.Contains(customerName)

假设,将为每个列表项检查string.IsNullOrWhiteSpace(customerName),而第一个仅检查一次。

答案 1 :(得分:0)

虽然它实际上看起来并不令人生畏。但想象一下,你在一家IT公司工作,你的老板要求你创建一个应用程序,你可以根据公司数据库中的任何可用标准搜索所有员工。好吧那并不难你有一个Employees表,你只需要搜索那里的字段。所以你创建一个应用程序并连接你的文本框来提供你的价值,并根据你查询数据库。你的老板很高兴,但仍然没有现在他很满意他希望你的应用程序基于多个列进行查询 - 以任何顺序并可能全部使用它们。因此,您允许用户从复选框列表中选择将包含在查询中的任何字段,并指定条件。解决此问题而不使用LINQ和PredicateBuilder基本上需要为每个编写查询变体列的可能组合。

PredicateBuilder只是简单地结合了不确定数量的标准。因此,当您向数据访问层编写代码时,您可能不希望更改整个代码,而只需更改谓词构建器类。

答案 2 :(得分:0)

在玩了这个之后,我发现两者之间存在重大差异,所以除非有人能指示我这样做,否则我不认为你可以使用Linq2Entities的谓词方法。

我创建了一个新的控制台应用程序,添加了连接到Chinook数据库的EF模型,并添加了以下代码......

  using (ChinookEntities ctx = new ChinookEntities()) {
    List<Func<Album, bool>> predicates = new List<Func<Album, bool>> {
      a => a.Title.Contains("AC"),
    };
    List<Album> albums = ctx.Albums.Where(c => predicates.All(p => p(c))).ToList();
  }
}

当您尝试运行此操作时,会出现以下异常...

&#34;无法创建类型&#39; System.Func`2 [[Chinook.Album,Chinook,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]的常量值, [System.Boolean,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]&#39;。在此上下文中仅支持原始类型或枚举类型。&#34;

看起来Linq2Entities并不支持这种方法 - 除非有人能告诉我如何解决这个问题。

希望这有助于某人。