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

EF Core中如何构建属性动态选择的Where谓词

问题解决:EF Core中表达式树无法翻译Invoke的问题

问题原因

你原来的方法接收Func<E, NpgsqlTsVector>类型的参数,返回的表达式树里会生成Invoke节点,EF Core无法将这种委托调用转换为对应的SQL语句,因此抛出无法翻译的错误。

解决方案

需要直接基于表达式树拼接调用逻辑,而非依赖委托调用。下面提供两种实现方式:

方式一:接收表达式lambda(推荐,调用更直观)

修改方法签名为接收Expression<Func<E, NpgsqlTsVector>>,手动构建调用Matches方法的表达式树:

using System.Linq.Expressions;
using NpgsqlTypes;

public Expression<Func<E, bool>> GetWherePredicate<E>(Expression<Func<E, NpgsqlTsVector>> selector, string queryText)
{
    // 获取实体参数(对应lambda里的entity)
    ParameterExpression entityParam = selector.Parameters[0];
    
    // 获取selector的表达式体(比如i => i.MySearchField中的i.MySearchField)
    Expression tsVectorExpression = selector.Body;
    
    // 获取NpgsqlTsVector的Matches方法(参数为string的重载)
    MethodInfo matchesMethod = typeof(NpgsqlTsVector).GetMethod(
        nameof(NpgsqlTsVector.Matches), 
        new[] { typeof(string) })!;
    
    // 构建调用Matches的表达式:tsVectorExpression.Matches(queryText)
    MethodCallExpression matchesCall = Expression.Call(
        tsVectorExpression, 
        matchesMethod, 
        Expression.Constant(queryText));
    
    // 最终构建返回的lambda表达式:entity => entity.MySearchField.Matches(queryText)
    return Expression.Lambda<Func<E, bool>>(matchesCall, entityParam);
}

调用方式和你原来的完全一致:

query = query.Where(GetWherePredicate<MyEntity>(i => i.MySearchField, "the_query"));

方式二:接收MemberExpression(按你需求的签名)

如果坚持使用MemberExpression作为参数,实现如下:

using System.Linq.Expressions;
using NpgsqlTypes;

public Expression<Func<E, bool>> GetWherePredicate<E>(MemberExpression selectorForSearchField, string queryText)
{
    // 校验传入的MemberExpression主体是E类型参数
    if (!(selectorForSearchField.Expression is ParameterExpression entityParam) || 
        entityParam.Type != typeof(E))
    {
        throw new ArgumentException("selectorForSearchField必须是E类型参数的成员表达式");
    }
    
    // 获取Matches方法
    MethodInfo matchesMethod = typeof(NpgsqlTsVector).GetMethod(
        nameof(NpgsqlTsVector.Matches), 
        new[] { typeof(string) })!;
    
    // 构建调用Matches的表达式
    MethodCallExpression matchesCall = Expression.Call(
        selectorForSearchField, 
        matchesMethod, 
        Expression.Constant(queryText));
    
    // 构建返回的lambda
    return Expression.Lambda<Func<E, bool>>(matchesCall, entityParam);
}

调用时需手动构建MemberExpression(不如方式一便捷):

ParameterExpression param = Expression.Parameter(typeof(MyEntity), "i");
MemberExpression memberExpr = Expression.PropertyOrField(param, nameof(MyEntity.MySearchField));
query = query.Where(GetWherePredicate<MyEntity>(memberExpr, "the_query"));

原理说明

通过直接拼接表达式树节点,EF Core可以完整解析MySearchField.Matches(queryText)的逻辑,将其转换为PostgreSQL对应的全文检索SQL,避免了无法翻译的Invoke节点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:15:33