contains("abc")生成like '%abc%',startswith("abc")生成like 'abc%',endswith("abc")生成like '%abc';变量场景下sql server用charindex、postgresql用position;需通配符或索引优化时必须用ef.functions.like()。

EF Core 里模糊查询不能靠手拼 "%abc%",也不能直接用 Regex 或内存过滤——否则整张表被拉到 C# 进程里筛,性能直接崩。
Contains、StartsWith、EndsWith 是怎么翻译成 SQL 的?
它们语义清晰,但底层生成的 SQL 不全是 LIKE,取决于你传的是字面量还是变量:
-
Contains("abc")(固定字符串)→ 多数数据库生成WHERE Name LIKE '%abc%' -
Contains(keyword)(变量)→ SQL Server 默认生成CHARINDEX(@p0, Name) > 0;PostgreSQL 可能用position($1 in Name) > 0 -
StartsWith("abc")→ 固定值时通常是LIKE 'abc%',变量时可能退化为LEFT(Name, LEN(@p0)) = @p0 - 这些方法不支持通配符
_或转义,也不控制大小写行为(由数据库排序规则决定)
什么时候必须用 EF.Functions.Like()?
当你需要真正等价于 SQL 的 LIKE 行为:带 %、_、自定义 ESCAPE,或想确保走索引前缀(比如 "abc%")时,就得用它:
- 只在 SQL Server / PostgreSQL 支持,SQLite 和 MySQL 需额外映射或改用原生 SQL
- 写法:
Where(u => EF.Functions.Like(u.Name, "%张%")),注意%是你手动拼的,不是自动加的 - 大小写敏感性完全由数据库字段 COLLATE 决定,EF 不干预
- 如果字段允许
NULL,Like(null, pattern)会返回NULL,查不到结果,得显式加u.Name != null && EF.Functions.Like(...)
空值、类型转换和性能陷阱
这几个点一漏就报错或查不准:
-
Contains(null)直接抛ArgumentNullException,必须前置判空:!string.IsNullOrEmpty(keyword) && u.Name.Contains(keyword) - 对非字符串字段(如
int、DateTime)做模糊查询,别写x.Age.ToString().Contains(...)——EF Core 会把它当客户端计算,全表加载后才过滤 - 想查日期“2026年4月”开头的数据,不要用
CreateTime.ToString().Contains("2026-04"),应改用CreateTime.Year == 2026 && CreateTime.Month == 4或数据库函数(如EF.Functions.DatePart("year", x.CreateTime)) - MySQL 用户注意:
EF.Functions.Like在 Pomelo.EntityFrameworkCore.MySql 中需启用UseMySql(..., mySqlOptions => mySqlOptions.EnableRetryOnFailure())并确认版本支持,旧版可能不识别
为什么 StartsWith 比 Contains 更快?
因为数据库能利用索引前缀加速 LIKE 'abc%',但对 LIKE '%abc%' 几乎无法索引。所以:
- 用户搜“姓名以张开头”,用
StartsWith("张")—— 走索引 - 用户搜“姓名含张”,只能用
Contains("张")或Like("%张%")—— 全表扫描风险高 - 如果字段建了全文索引(SQL Server 的
FULLTEXT,PostgreSQL 的tsvector),就别用模糊查询,改用EF.Functions.FreeText或EF.Functions.ToTsVector
最易被忽略的一点:EF Core 查询是否真正下推到数据库,不能只看代码写了 Where,得看生成的 SQL——用 EnableDetailedErrors() 或日志输出验证,否则你以为在查库,其实是在内存筛百万行。











