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

如何将MethodInfo结果赋值给属性以实现Entity Framework动态查询?

问题描述

目标是实现更具动态性和面向对象的Entity Framework数据库查询,编写了如下类:

class Target
{
    [MapFrom(nameof(GetSum))]
    public int Sum { get; set; }
    public static Expression<Func<int>> GetSum(Source s) => () => s.First + s.Second;
}

希望生成如下形式的表达式之一:

dbContext.Table.Select(x => {Sum = x.First + x.Second })

or 

dbContext.Table.Select(x => {Sum = GetSum(x) })

尝试构建x => {Sum = GetSum(x)}表达式来为属性赋值,编写了如下方法:

private static MemberBinding _getMethodAssigned(
    string propertyName,              // this is Sum
    MethodInfo methodInfo,            // this is the MethodInfo of GetSum
    ParameterExpression parameter,    // this is the x
    Type type                         // this is the type Target
    )
{
    MethodCallExpression methodCallExpression = Expression.Call(null, methodInfo, parameter);
    MemberInfo member = type.GetMember(propertyName).First();
    return Expression.Bind(member, methodCallExpression);
}

但该方法无法正常工作,因为Sum属性类型为int,而GetSum方法返回类型为Expression<Func<int>>,实际想要的是将GetSum的执行结果赋值给Sum,请问该如何实现?

解决方案

问题核心在于GetSum返回的是Expression<Func<int>>,而非直接的int值,我们需要针对EF查询的场景做不同处理:

方案1:提取表达式内部逻辑(适配EF数据库查询,推荐)

EF需要将表达式解析为SQL,直接执行表达式会导致无法转换,因此最优方式是提取GetSum返回表达式的Body部分,直接用于赋值:

private static MemberBinding _getMethodAssigned(
    string propertyName,
    MethodInfo methodInfo,
    ParameterExpression parameter,
    Type type
)
{
    // 调用GetSum方法,得到Expression<Func<int>>实例的表达式
    var getSumCall = Expression.Call(null, methodInfo, parameter);
    // 提取该表达式的Body部分(即s.First + s.Second的逻辑)
    var expressionBody = Expression.Property(getSumCall, "Body");
    
    MemberInfo member = type.GetMember(propertyName).First();
    // 直接用提取后的逻辑作为Sum属性的赋值来源
    return Expression.Bind(member, expressionBody);
}

最终生成的表达式等价于x => new Target { Sum = x.First + x.Second },完全兼容EF的SQL解析逻辑。

方案2:编译执行表达式(仅适用于内存集合)

如果是对内存中的集合进行操作(比如已调用ToList()之后),可以编译并执行GetSum返回的表达式来获取int值:

private static MemberBinding _getMethodAssigned(
    string propertyName,
    MethodInfo methodInfo,
    ParameterExpression parameter,
    Type type
)
{
    // 调用GetSum得到Expression<Func<int>>的表达式
    var getSumCall = Expression.Call(null, methodInfo, parameter);
    // 构建编译表达式并执行的逻辑:expression.Compile().Invoke()
    var compileMethod = typeof(Expression).GetMethod("Compile", Type.EmptyTypes);
    var compileCall = Expression.Call(getSumCall, compileMethod);
    var invokeMethod = typeof(Delegate).GetMethod("Invoke");
    var invokeCall = Expression.Call(compileCall, invokeMethod);
    
    MemberInfo member = type.GetMember(propertyName).First();
    return Expression.Bind(member, invokeCall);
}

注意:此方案不能用于EF数据库查询,因为EF无法将Compile()和Invoke()解析为SQL语句。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 06:05:17