Contains 不能当 SQL LIKE 用,因其仅作字面子串匹配、不支持通配符和大小写控制,等价于 IndexOf>=0;实现 LIKE 需手动转义为正则或使用 EF.Functions.Like。

Contains 为什么不能当 SQL LIKE 用
Contains 是 string 类型的实例方法,只做子串存在性判断,不支持通配符、不区分大小写控制、也不支持开头 / 结尾锚定。它等价于 IndexOf(……) >= 0,不是模糊匹配引擎。
常见错误现象:想用 "abc".Contains("a_c") 匹配类似 “abc” 或 “axc”,结果返回 false —— 因为 Contains 把 "a_c" 当作字面量,下划线没有特殊含义。
- 使用场景:仅适用于“这个子字符串是否原样出现”的简单判断
- 参数差异:
Contains没有重载支持StringComparison(.NET 5+ 才有),老版本需改用IndexOf(……, StringComparison.OrdinalIgnoreCase) - 性能影响:极快,是 O(n) 的朴素搜索;但别指望它替代正则或模式匹配
想实现 LIKE 语义,得自己转义或用 Regex
SQL 的 LIKE 'a%b_c' 中,% 匹配任意长度字符,_ 匹配单个字符。C# 没内置等价物,必须手动映射到 Regex。
关键点:不能直接把 % 和 _ 塞进 Regex.IsMatch,它们在正则里有不同含义(% 不是元字符,_ 是字面量),得先转义再替换:
-
%→.*(注意:开头结尾通常要加^和$锚定,否则变成“包含”而非“匹配”) -
_→. - 原始字符串中的
.、^、$等正则元字符需先用Regex.Escape()处理
示例:LikeMatch("hello world", "he%wor_d") 应返回 true,内部会转成正则 ^he.*wor.d$。
EF Core 查询中用 SqlFunctions.Like 会更安全
如果是在 EF Core 的 LINQ 查询里做数据库侧模糊匹配,别在内存里用 Regex 或循环过滤,那会把整张表拉到客户端。应该用数据库原生 LIKE。
.NET 6+ 提供了 EF.Functions.Like,它生成的是 SQL LIKE 表达式,由数据库执行:
context.Users.Where(u => EF.Functions.Like(u.Name, "Jo%"))
注意点:
- 该调用只在 EF Core 查询中有效,不能用于纯内存集合(
List<T>) - 通配符
%和_直接写,不用转义;但若要匹配字面量%,需指定 escape 字符,如EF.Functions.Like(u.Name, "10!%", "!") - 性能取决于数据库索引,前导通配符(如
"%o%")通常无法走索引
别忽略文化敏感性和大小写问题
字符串比较默认受当前线程 CultureInfo 影响。比如土耳其语环境下,"i".ToUpper() 不是 "I",可能导致 Contains 或正则意外失败。
实际编码中容易被忽略的地方:
- 用
StringComparison.Ordinal或StringComparison.OrdinalIgnoreCase显式指定比较方式,避免隐式依赖本地文化 -
Regex默认区分大小写,需要模糊匹配时加RegexOptions.IgnoreCase - 数据库
LIKE的大小写行为取决于字段 collation,EF Core 不会自动适配,得确认数据库配置
最麻烦的其实是跨层一致性:前端传的 pattern、C# 正则处理、数据库 LIKE 解释,三者对大小写和空格的容忍度可能不一致,调试时容易卡在某一层的隐式转换上。