【问题标题】:LINQ multiple where clauseLINQ 多个 where 子句
【发布时间】:2010-10-10 12:26:00
【问题描述】:

我有一个课程表,我需要根据在搜索框中输入的关键字进行搜索。 这是一个示例查询:

SELECT * FROM Courses WHERE 
Title LIKE '%word%' OR Title LIKE '%excel%' OR 
Contents LIKE '%word%' OR Contents LIKE '%excel%'

如何在 LINQ 中转换它,其中 LINQ 会根据每个关键字动态生成 W​​HERE 语句。

我尝试使用 PredicateBuilder,只要字段是 VARCHAR,它就可以正常工作。对于“TEXT”字段,不会生成引号,从而导致编译器给出错误消息。这是 PredicateBuilder 生成的 SQL

SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active], 
FROM [dbo].[Courses] AS [t0]
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR 
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%)

请注意,数据库中的文本字段“内容”字段没有单引号。

是否有任何简单的方法来构建 WHERE 语句并将其附加到查询中?有谁知道我如何在没有 PredicateBuilder 的情况下做到这一点?

提前致谢。

【问题讨论】:

    标签: linq where-clause


    【解决方案1】:

    由于您正在使用 LINQ,我想您正在使用 LINQ-to-SQL 数据上下文,对吧?我没有备用的 DataContext 来测试这个,但这应该会给你一些想法。

    虽然我不知道它是否适用于数据上下文,但其中大部分都是非常基本的东西(链接 OR 运算符和 Contains 方法调用),因此当查询转换为 SQL 时它不会引起问题。

    首先我创建一个自定义函数来构建我的谓词:

    Func<string, Func<DataItem, bool>> buildKeywordPredicate =
        keyword =>
            x => x.Title.Contains(keyword)
                || x.Contents.Contains(keyword);
    

    这是一个函数,它接受一个字符串关键字,然后返回另一个函数,该函数接受一个 DataItem 并根据关键字检查它。

    基本上,如果你传入“Stack”,你会得到一个谓词:x =&gt; x.Title.Contains("Stack") || x.Contents.Contains("Stack")

    接下来,由于有许多可能的关键字,并且您需要使用 OR 操作将其链接起来,因此我创建了另一个辅助函数来将 2 个谓词与 OR 链接在一起

    Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
        (pred1, pred2) =>
            x => pred1(x) || pred2(x);
    

    这个函数接受 2 个谓词,然后用 OR 操作将它们连接起来。

    有了这两个函数,我可以像这样构建我的 where 谓词:

    foreach (var word in keywords) {            
        filter = filter == null
            ? buildKeywordPredicate(word)
            : buildOrPredicate(filter, buildKeywordPredicate(word));
    }
    

    循环内的第一行主要检查过滤器是否为空。如果是,那么我们需要为我们构建一个简单的关键字过滤器。

    否则,如果过滤器不为空,我们需要使用 OR 操作链接现有过滤器,因此我们将现有过滤器和新关键字过滤器传递给 buildOrPredicate 来做到这一点。

    然后我们现在可以创建查询的 WHERE 部分:

    var result = data.Where(filter);
    

    传入我们刚刚构建的复杂谓词。

    我不知道这是否与使用 PredicateBuilder 不同,但由于我们将查询转换推迟到 LINQ-to-SQL 引擎,所以应该不会有任何问题。

    但正如我所说,我还没有针对真实的数据上下文对其进行测试,所以如果有任何问题可以在 cmets 中编写。

    这是我为测试而构建的控制台应用:http://pastebin.com/feb8cc1e

    希望这会有所帮助!


    编辑:有关在 LINQ 中正确利用表达式树的更通用和可重用的版本,请查看 Thomas Petricek 的博客文章:http://tomasp.net/articles/dynamic-linq-queries.aspx

    【讨论】:

    • 不幸的是,这仅适用于函数。要使用表达式树,您需要使用这样的技巧:tomasp.net/articles/dynamic-linq-queries.aspx
    • 那是你在那里所做的一些壮举!.. 同样的技巧,但更通用,更棒......无论如何,我现在是你博客的订阅者 :-)
    • 谢谢,这个成功了。 tomasp.net/articles/dynamic-linq-queries.aspx – Tomas Petricek
    • 我正在寻找一个简单的解决方案。类似于: var q = q.Where() 如何编写自定义 Where 语句并将其附加到 LINQ?
    • 返回 IEnumerable,我正在寻找 IQueryable。因此,我尝试将其封装在一个 Expression 中,但得到了 SQL 无法弄清楚 .Invoke 是什么的异常,这是有道理的,但我不知道下一步该做什么(除了放弃此方法)。
    【解决方案2】:

    由于谓词构建器不知道调用 Contains 方法的属性的 DB 类型,我想这可能是 linq to sql 内部的问题。您是否尝试过使用普通查询(不是使用谓词构建器)和包含包含的 TEXT 列?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-06
      • 2017-08-24
      相关资源
      最近更新 更多