【问题标题】:How do I escape a LIKE clause?如何转义 LIKE 子句?
【发布时间】:2011-01-30 09:10:26
【问题描述】:

我们在这部分搜索查询中使用的代码很简单:

myCriteria.Add(
    Expression.InsensitiveLike("Code", itemCode, MatchMode.Anywhere));

这在生产环境中运行良好。

问题是我们的一位客户的商品代码包含此查询需要匹配的 % 符号。此代码生成的 SQL 输出类似于:

SELECT ... FROM ItemCodes WHERE ... AND Code LIKE '%ItemWith%Symbol%'

这清楚地解释了为什么他们在项目搜索中得到一些奇怪的结果。

有没有办法使用编程的Criteria 方法启用转义?


附录:

我们使用的是稍旧的 NHibernate 版本,2.1.0.4000(目前为 2.1.2.4853),但我查看了发行说明,并没有提及对此的修复。我也没有在他们的 bugtracker 中发现任何未解决的问题。

我们使用的是 SQL Server,所以我可以很容易地转义代码中的特殊字符(%、_、[ 和 ^),但我们使用 NHibernate 的目的是使我们的应用程序数据库引擎独立于尽可能的。

Restrictions.InsensitiveLike()HqlQueryUtil.GetLikeExpr() 都不会转义它们的输入,删除 MatchMode 参数对转义没有任何影响。


我发现someone else 想要做同样的事情(三年前),解决方案是将escapeChar 重载添加到我上面提到的方法中(这在版本 2.0.0.3347 中已“修复” )。我对该问题添加了一条评论,要求进一步解决。

【问题讨论】:

    标签: .net nhibernate criteria


    【解决方案1】:

    我能找到实现数据库独立性的唯一方法是转义搜索字符串中的每个字符并在 LikeExpression 上调用适当的构造函数,就像我之前的回答一样。您可以手动执行此操作或扩展 LikeExpression:

        public class LikeExpressionEscaped : LikeExpression
        {
            private static string EscapeValue(string value)
            {
                var chars = value.ToCharArray();
                var strs = chars.Select(x => x.ToString()).ToArray();
                return "\\" + string.Join("\\", strs);
            }
    
            public LikeExpressionEscaped(string propertyName, string value, MatchMode matchMode, bool ignoreCase)
                : base(propertyName, EscapeValue(value), matchMode, '\\', ignoreCase)
            {}
        }
    

    毫无疑问,有一种更有效的方法来创建转义字符串(请参阅this question 的答案和 cmets)。用法是:

    var exp = new LikeExpressionEscaped("Code", itemCode, MatchMode.Anywhere, true);
    myCriteria.Add(exp);
    

    【讨论】:

    • 杰米,感谢您的帮助。看来我正在寻找的东西不存在(请参阅我在问题正文中的更新)。你在这里给出的方法是我要采用的方法。我暂时将这个答案标记为已接受,如果 NHibernate 的作者决定做任何事情,我会在那时重新讨论这个问题。
    • 对于未来的访问者:使用 .NET 4,您可以简单地使用 return @"\" + string.Join( @"\", value.ToCharArray() )。更干净,性能更好。
    • 不会将空字符串转换为“\\”吗?
    【解决方案2】:

    您可以创建一个 LikeExpression 实例来完成此操作。在这个例子中,我用反斜杠转义 %(它本身必须被转义):

    var itemCode = "ItemWith%Symbol";
    itemCode = searchCode.Replace("%", "\\%");
    var exp = new LikeExpression("Code", itemCode, MatchMode.Anywhere, '\\', true);
    myCriteria.Add(exp);
    

    我没有看到使用此重载返回 LikeExpression 的静态方法。

    顺便说一句,如果您使用的是 SQL Server,则默认情况下不区分大小写。

    【讨论】:

    • 感谢您的回复。我们正在使用 SQL Server,但正如我所说,使用 NHibernate 的目的是使我们的后端数据库与数据库无关。我更喜欢基于所选 NHibernate 方言的解决方案。在 SQL Server 中,[ 字符也是转义字符。我想逃避其他方言中的那些会起作用......但它并不是很干净,如果你知道我的意思的话。由于我们已经通过数据层调用了这些对 LikeInsensitiveLike 的调用,因此最好使用内部函数/选项来执行此操作,而不是自己滚动。
    • 乔恩,我不明白你的评论。我的回答是不区分大小写的 LIKE——为 ignoreCase 提供了真正的最终参数:public LikeExpression(string propertyName, string value, char? escapeChar, bool ignoreCase)。我只是指出它对 SQL Server 没有影响。 InsensitiveLikeExpression 上没有接受转义字符的重载构造函数。
    • 我明白这一点。我要说的是 SQL Server 有一个额外的转义字符 ([),而其他引擎没有。我想至少要在其中获得一个转义字符,所有现有代码都必须更改,但对于 SQL Server 以外的引擎,如果我不需要,我宁愿不转义 [
    • 好的,我明白了。我认为只有通配符会出现 LIKE 问题,但事实并非如此。如果我想出一个好的答案,我会添加一个新的答案。
    猜你喜欢
    • 2014-05-10
    • 2023-01-26
    • 2010-10-01
    • 2011-03-01
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多