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

.NET 6升级后EF.Functions.Like方法报错:不支持客户端评估

解决.NET 6中EF.Functions.Like触发客户端求值的异常

你遇到的InvalidOperationException: The Like method is not supported because the query has switched to client-evaluation异常,核心原因是你将表达式树编译成了委托,导致EF Core无法解析EF.Functions.Like并转换为SQL语句,只能退化为客户端求值,而.NET 6的EF Core默认禁止这种无法翻译的客户端求值行为(ASP.NET Core 3.1的EF Core对这类情况限制更宽松)。

具体来说,代码中的var predicateCompiled = predicate.Compile();把Expression<Func<Evidence, bool>>转换成了Func<Evidence, bool>,当你把这个委托传给Where方法时,EF Core无法分析其中的表达式逻辑,自然无法将EF.Functions.Like翻译成SQL的LIKE操作符,只能在内存中过滤数据,而此时EF.Functions.Like无法在客户端环境中执行,最终抛出异常。


解决方案

1. 移除Compile()调用,直接使用表达式树

EF Core的Where方法支持直接传入Expression<Func<T, bool>>,这样EF Core可以完整解析表达式树并转换为对应的SQL语句。修改你的查询方法:

public static IQueryable<Evidence> QueryEvidences(this EvidenceContext Context, EvidenceQuery query)
{
    var predicate = PredicateBuilder.True<Evidence>();
    predicate = predicate.And(x => x.IsActive && x.EvidenceStatus != EvidenceStatus.ReleasedToOwner && x.EvidenceStatus != EvidenceStatus.Transfer);
    if (query.EvidenceStatus is not EvidenceStatus.Disposed)
    {
        predicate = predicate.And(x => x.IsActive && x.EvidenceStatus != EvidenceStatus.Disposed);
    }
    if (query.EvidenceStatus is not EvidenceStatus.Incoming)
    {
        predicate = predicate.And(x => x.IsActive && x.EvidenceStatus != EvidenceStatus.Incoming);
    }

    var predicateAndOr = query.IsOr ? PredicateBuilder.False<Evidence>() : PredicateBuilder.True<Evidence>();

    if (!string.IsNullOrWhiteSpace(query.CaseNumber))
    {
        predicateAndOr = predicateAndOr.AndOr(x => EF.Functions.Like(x.CaseFileNumber, $"%{query.CaseNumber}%"), query.IsOr);
    }

    predicate = predicate.And(predicateAndOr);

    // 直接使用predicate表达式树,不要调用Compile()
    return query.IncludeRequests
        ? Context.Evidences.Include(x => x.Requests).AsNoTracking().Where(predicate).OrderByDescending(x => x.Modified)
        : Context.Evidences.Where(predicate).OrderByDescending(x => x.Modified);
}

注:IQueryable是延迟执行的,方法无需标记为async,异步操作应该在最终执行查询时(比如调用ToListAsync())使用。

2. 优化PredicateBuilder(可选但推荐)

你当前的PredicateBuilder使用了Expression.Invoke拼接表达式,虽然大部分场景下EF Core可以处理,但复杂场景下可能影响表达式翻译。可以替换为更可靠的参数替换式拼接:

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() => _ => true;
    public static Expression<Func<T, bool>> False<T>() => _ => false;

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
    {
        var combined = Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(left.Body, new ParameterReplacer(right.Parameters[0], left.Parameters[0]).Visit(right.Body)),
            left.Parameters);
        return combined;
    }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
    {
        var combined = Expression.Lambda<Func<T, bool>>(
            Expression.OrElse(left.Body, new ParameterReplacer(right.Parameters[0], left.Parameters[0]).Visit(right.Body)),
            left.Parameters);
        return combined;
    }

    public static Expression<Func<T, bool>> AndOr<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2, bool or = false)
    {
        return or ? expr1.Or(expr2) : expr1.And(expr2);
    }

    private class ParameterReplacer : ExpressionVisitor
    {
        private readonly ParameterExpression _oldParam;
        private readonly ParameterExpression _newParam;

        public ParameterReplacer(ParameterExpression oldParam, ParameterExpression newParam)
        {
            _oldParam = oldParam;
            _newParam = newParam;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == _oldParam ? _newParam : base.VisitParameter(node);
        }
    }
}

这个版本通过替换参数直接拼接表达式体,避免了Expression.Invoke,让EF Core更容易翻译表达式树。


验证

修改后,EF Core会将EF.Functions.Like(x.CaseFileNumber, $"%{query.CaseNumber}%")正确转换为SQL的WHERE CaseFileNumber LIKE '%xxx%',完全在数据库端执行查询,不会触发客户端求值。

内容的提问来源于stack exchange,提问作者Muhammad Touseef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:45:33