如何用EF Core表达式树实现非字符串列的字符串模糊查询?
解决EF Core表达式树实现非字符串列模糊查询的问题
可以实现你想要的SQL查询效果,你之前遇到的异常是因为Expression.Convert是CLR层面的类型转换操作,EF Core无法将其映射为SQL的CAST,且CLR本身没有内置值类型(如int、bool)到string的强制转换操作符,因此抛出错误。
以下是正确的实现方案:
核心思路
- 字符串类型属性:直接使用
string.Contains生成LIKE '%xxx%'(EF Core会自动转换该方法为SQL LIKE语句)。 - 非字符串类型属性:通过
Convert.ToString将属性转换为字符串(EF Core会将其翻译为SQL的CAST操作),再结合EF.Functions.Like实现模糊匹配,以此生成你需要的CAST([列] AS varchar) LIKE '%xxx%'语句。
完整代码示例
using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; public static class QueryableExtensions { public static IQueryable<T> SearchAllColumns<T>(this IQueryable<T> query, string searchValue) { if (string.IsNullOrWhiteSpace(searchValue)) return query; // 构建带通配符的查询值 var likeValue = $"%{searchValue}%"; var parameter = Expression.Parameter(typeof(T), "x"); Expression? combinedExpression = null; // 获取EF.Functions.Like方法的反射信息 var likeMethod = typeof(DbFunctionsExtensions) .GetMethod(nameof(DbFunctionsExtensions.Like), new[] { typeof(DbFunctions), typeof(string), typeof(string) })!; // 获取string.Contains方法的反射信息 var containsMethod = typeof(string) .GetMethod(nameof(string.Contains), new[] { typeof(string) })!; foreach (var prop in typeof(T).GetProperties()) { var propertyExpr = Expression.PropertyOrField(parameter, prop.Name); Expression? matchExpr = null; if (prop.PropertyType == typeof(string)) { // 字符串列直接调用string.Contains matchExpr = Expression.Call( propertyExpr, containsMethod, Expression.Constant(searchValue, typeof(string))); } else { // 非字符串列:先调用Convert.ToString转成字符串,再用EF.Functions.Like匹配 var toStringCall = Expression.Call( typeof(Convert), nameof(Convert.ToString), new[] { prop.PropertyType }, propertyExpr); matchExpr = Expression.Call( likeMethod, Expression.Constant(EF.Functions), toStringCall, Expression.Constant(likeValue, typeof(string))); } // 用OR拼接所有列的匹配条件 combinedExpression = combinedExpression == null ? matchExpr : Expression.OrElse(combinedExpression, matchExpr); } if (combinedExpression != null) { var lambda = Expression.Lambda<Func<T, bool>>(combinedExpression, parameter); query = query.Where(lambda); } return query; } }
效果验证
使用该方法查询UploadedFile时,生成的SQL会和你期望的完全一致:
SELECT * FROM [joint].[UploadedFile] AS [u] WHERE (CAST([u].[ID] AS varchar(11)) LIKE N'%.pdf%') OR (CAST([u].[Size] AS varchar(30)) LIKE N'%.pdf%') OR (CAST([u].[IsValid] AS varchar(5)) LIKE N'%.pdf%') OR (CAST([u].[DateOfUpload] AS varchar(23)) LIKE N'%.pdf%') OR ([u].[FileName] LIKE N'%.pdf%') OR ([u].[Type] LIKE N'%.pdf%');
注意事项
- 确保你的EF Core版本在2.0及以上,该版本开始支持
Convert.ToString到SQLCAST的转换映射。 - 对于日期类型,转换后的字符串格式取决于数据库的默认日期格式,若需要指定格式,可以替换为
DbFunctions.ToString方法并传入格式参数。
内容的提问来源于stack exchange,提问作者Goran Petrović
相关产品推荐
相关产品推荐

