You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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到SQL CAST的转换映射。
  • 对于日期类型,转换后的字符串格式取决于数据库的默认日期格式,若需要指定格式,可以替换为DbFunctions.ToString方法并传入格式参数。

内容的提问来源于stack exchange,提问作者Goran Petrović

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 13:05:55