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

如何为LINQ连接生成的匿名类型动态构造表达式树?

解决匿名类型动态Lambda表达式的问题

我之前也碰到过一模一样的困扰——用LINQ连接两个实体类后,没法给返回的匿名类型动态生成Lambda表达式做过滤,因为匿名类型的字段没有预定义,动态表达式根本找不到对应的属性,传object或者dynamic都会直接抛出异常。

先说说我的初始场景

先给大家看下我用到的实体类:

public class Book { 
    public int BookID { get; set; } 
    public string Author { get; set; } 
    public string Publisher { get; set; } 
}

public class Library { 
    public int ID { get; set; } 
    public Book Book { get; set; } 
    public int Count { get; set; } 
}

还有那个动态生成Lambda的函数,单独查询Book或者Library的时候完全正常:

public static Expression<Func<T, bool>> GetLambdaExpression<T>(List<Operation> OperationList) {
    ExpressionTree expressionTree = new ExpressionTree();
    Node Root = expressionTree.ConstructTree(OperationList);
    var Parameter = Expression.Parameter(typeof(T), "x");
    var Expression = CalculateExpression(Root); // 通过And/Or组合OperationList中的输入生成表达式子句
    return Expression.Lambda<Func<T, bool>>(Expression, Parameter); // 最终创建Lambda
}

但一旦做实体连接,返回匿名类型后就彻底失效了:

// 这段代码无法正常运行
var result = from c in _BookContext.Books join d in _LibraryContext.Library on c.BookID equals d.ID select new { c , d };
var OperationList = // 客户端传递的过滤条件
var LambdaExpression = GetLambdaExpression<object>(OperationList); // 传object/dynamic都会报错
result.Where(LambdaExpression);

我的解决方案

后来我换了个思路,放弃匿名类型,专门创建一个包含连接实体的类:

public class JoinResult { 
    public Book Book { get; set; } 
    public Library Library { get; set; } 
}

然后把连接结果映射到这个类里:

var result = from c in _BookContext.Books 
             join d in _LibraryContext.Library on c.BookID equals d.ID 
             select new JoinResult{ Book = c , Library = d };

接下来是关键步骤:修改动态表达式的生成逻辑,处理嵌套属性(比如x.Book.BookID这种多层属性)。举个Equal操作的实现例子:

public static IQueryable<T> PerformEqualOperation<T>(int Constant, string FieldName, Type Prop, IQueryable<T> resultOfJoin) {
    var Parameter = Expression.Parameter(typeof(T), "x"); // 对应表达式中的x
    // 获取JoinResult的所有属性
    PropertyInfo[] Properties = typeof(T).GetProperties(); 
    string propertyname = string.Empty;
    // 找到匹配目标类型的属性名(比如Prop是Book类型,就找到JoinResult里的Book属性)
    foreach(var property in Properties) {
        if(property.PropertyType == Prop) {
            propertyname = property.Name;
            break;
        }
    }
    // 构建第一层属性表达式:x.Book
    var expressionparameter = Expression.Property(Parameter, propertyname); 
    // 构建深层属性表达式:x.Book.BookID
    var expressionproperty = Expression.Property(expressionparameter, FieldName);
    // 构建等于条件表达式:x.Book.BookID == Constant
    var expressionclause = Expression.Equal(expressionproperty, Expression.Constant(Constant));
    // 生成最终的Lambda表达式
    var expressionlambda = Expression.Lambda<Func<T,bool>>(expressionclause, Parameter);
    return resultOfJoin.Where(expressionlambda).AsQueryable();
}

这样就能正常对连接后的结果进行动态条件过滤了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:22:44