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

多表连接LINQ查询中构建含Where子句的Lambda表达式问题

问题

需要在多表连接的LINQ查询中,为db1表添加Where()子句,原查询代码如下:

var query = from db1 in db.db1
            join db2 in db.database2 on db1.atr1 equals db2.atr1
            join db3 in db.database3 on db1.atr1 equals db3.atr1
            select new { db1, db2, db3};

在无连接的查询中,构建Lambda表达式的Where子句可以直接写:

query = query.Where(t => t.attr5.Contains("String"));

但多表连接后,正确的写法应该是:

query = query.Where(t => t.db1.attr5.Contains("String"));

当前用表达式树构建Where子句的代码会抛出类型不匹配错误:

ParameterExpression eParam = Expression.Parameter(tableType, "innerTable");
MethodInfo method = filterValue.GetType().GetMethod("Contains", new Type[] { typeof(string) }); // filterValue is just a string
MethodCallExpression call = Expression.Call(Expression.Property(eParam, filterField), method, Expression.Constant(filterValue));
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, eParam);
currentQuery = currentQuery.Where(lambda);

问题出在tableType和select new { db1, db2, db3 }生成的匿名类型不匹配,需要调整表达式树的构建逻辑。

解决方案

核心是先通过匿名类型的参数表达式获取db1属性,再链式访问db1的目标字段,具体步骤如下:

  1. 修正参数表达式的类型
    参数表达式的类型必须是匿名类型(即查询结果的元素类型typeof(T)),而非db1的类型:
ParameterExpression eParam = Expression.Parameter(typeof(T), "item");
  1. 链式获取目标属性
    先获取匿名类型中的db1属性,再获取db1的目标字段(比如attr5):
// 获取匿名类型的db1属性
Expression db1Expr = Expression.Property(eParam, "db1");
// 获取db1的目标字段
Expression targetAttrExpr = Expression.Property(db1Expr, filterField); // filterField为目标字段名,比如"attr5"
  1. 构建Contains方法调用
    直接获取string类型的Contains方法,避免通过filterValue的类型获取(防止类型不一致):
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
MethodCallExpression containsCall = Expression.Call(targetAttrExpr, containsMethod, Expression.Constant(filterValue));
  1. 构建Lambda并应用到查询
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(containsCall, eParam);
currentQuery = currentQuery.Where(lambda);

完整修正代码

// T为匿名类型,可通过currentQuery.ElementType获取,或由编译器自动推断
ParameterExpression eParam = Expression.Parameter(typeof(T), "item");
// 链式访问item.db1.filterField
Expression db1Property = Expression.Property(eParam, "db1");
Expression targetProperty = Expression.Property(db1Property, filterField);
// 获取String.Contains方法
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
MethodCallExpression containsCall = Expression.Call(targetProperty, containsMethod, Expression.Constant(filterValue));
// 构建Lambda表达式
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(containsCall, eParam);
// 应用Where子句
currentQuery = currentQuery.Where(lambda);

关键说明

原来的代码错误地将参数表达式的类型设为db1的类型,但查询的元素是匿名类型,所以必须以匿名类型作为参数,再通过属性访问拿到db1对象,之后才能访问db1的字段,这样就能解决类型不匹配的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 21:46:06