如何创建c# LambdaExpression,为SelectMany resultSelector返回匿名类型

本文关键字:resultSelector SelectMany 返回 类型 LambdaExpression 何创建 创建 | 更新日期: 2023-09-27 18:19:06

我正在构建一个动态查询,可以有nWhere方法调用和nSelectMany调用依赖于用户输入。例如:

var qZ = entityContext.TableA
        .SelectMany(a=>a.TableB, (a,t)=>new{a,t}  )
        .Where(a=>a.t.FieldID==21)
        .Where(a=> EntityFunctions.Left(a.t.Value,1)=="p")
        .SelectMany(a=>a.a.TableC, (a,t)=>new{a,t}  )
        .Where(a=>a.t.FieldID==22)
        .Where(a=> a.a.t.Value=="Peter" && a.t.Value=="Pan")
        .Where(a=> a.a.a.TypeID==3)
        .Select(a=> new{ a.a.a.ItemID }
        ).Distinct();

在我正在编写的方法中,我使用返回IQueryable的助手方法,如下面的返回行所示。

return query.Provider.CreateQuery(
    Expression.Call(typeof(Queryable), 
      "Where", 
       new Type[] {query.ElementType}, 
       query.Expression, predicateLambda)
           );

我能够为所需的所有各种查询属性值对创建LambdaExpressions,但我无法为Queryable.SelectManyresultSelector创建一个。

如何在表达式树中创建(a,t) => new{a=a, t=t} ?或者我们如何使用表达式实现与上面的. selectmany相同的结果。呼叫如下?

Expression.Call(typeof(Queryable), 
      "SelectMany", 
       ????????, 
       ????????
           );

我尝试使用SelectMany重载,不需要resultSelector在某种程度上起作用,但是,我不知道如何在随后的方法调用中引用t的属性。

我发现这个lambda表达式((a,t) => new{a=a, t=t})与SelectMany相关,但我找不到任何如何将其转换为表达式树的例子。

更新:让我们重新定义这个问题。我可以像这样传递

var q = entityContext.TableA.AsQueryable();
var q1 = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
var q2 = Queryable.Where(q1,a=>a.t.FieldID==22);

这是有效的,然而,因为我不知道有多少SelectMany需要调用,因为每次调用更改为iquerable的匿名类型,是否有一种方法将匿名类型强制转换(和重新强制转换)到单个变量?通过这种方式,我可以循环并应用变量所需的任何方法,然后在构建查询后枚举以获得结果。比如:

var q = entityContext.TableA..AsQueryable();
q = Queryable.SelectMany(q, a => a.TableB, (a, t) => new { a = a, t = t });
q = Queryable.Where(q,a=>a.t.FieldID==22);

(顺便说一句:这行不通)

如何创建c# LambdaExpression,为SelectMany resultSelector返回匿名类型

我最终解决这个问题的方法需要一个范式转换。上面的第一个查询是基于这样一个事实:我学会了通过将我需要的所有表连接在一起来编写查询,以便访问这些表中的过滤和选择字段。

SelectMany()在需要对表中的特定列进行过滤时,创建了连接,并围绕我的想法创建了方框,我必须将该表连接到我的查询。这反过来又改变了IQueryable的类型,导致我无法在设计时预测IQueryable的类型。

答:

步骤1:将IQueryable类型设置为它需要返回的输出类型。在上面的例子中,结果总是可查询的。

步骤2:利用Expressions动态创建WHERE谓词,包括创建适当过滤器所需的任何和所有表。这总是返回Expression>和我们容易考虑到的所有其他变量。请记住,在EF中,如果只需要在Where()中连接表,则不需要在Where()之外连接表。