如何创建为SelectMany resultSelector返回匿名类型的C#LambdaExpression

时间:2011-12-29 14:35:24

标签: c# linq

我正在构建一个动态查询,其中{strong} n 的Where方法调用和 n SelectMany调用取决于用户输入。例如,我可能有:

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,但我无法为resultSelector Queryable.SelectMany创建一个。

我们如何在表达式树中创建(a,t) => new{a=a, t=t}?或者我们如何使用Expression.Call完成与上面的.SelectMany相同的结果?如下所示?

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

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

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

更新: 让我们重新构思这个问题。我可以像这样传递lambda

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,并且由于每次调用都更改为IQueriable的匿名类型,是否有一种方法可以强制转换(并重新强制转换)匿名键入一个变量?这样我就可以遍历并应用变量所需的任何方法,然后枚举以在构建查询后获得结果。类似的东西:

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);

(顺便说一句:这不起作用)

1 个答案:

答案 0 :(得分:0)

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

SelectMany()创建连接,并且当时我的想法是必要的,如果我需要过滤表中的特定列,我必须将该表连接到我的查询。这反过来改变了我的IQueryable的类型,导致我无法在设计时预测IQueryable的类型。

答案:

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

步骤2:利用表达式动态创建WHERE谓词,包括创建正确过滤器所需的所有表。这总是返回Expression>以及我们容易解释的所有其他变量。并且记住,在EF中,如果仅在Where()中需要它们,则不必在Where()之外连接表。