【发布时间】:2013-02-24 02:06:45
【问题描述】:
下面的代码块回答了这个问题:“How do you perform a left outer join using linq extension methods?”
var qry = Foo.GroupJoin(
Bar,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(x,y) => new { Foo = x, Bars = y })
.SelectMany(
x => x.Bars.DefaultIfEmpty(),
(x,y) => new { Foo = x, Bar = y});
你如何将这个 GroupJoin 和 SelectMany 写成 MethodCallExpressions?我发现All of the examples 是使用 DynamicExpressions 将字符串转换为 lambda (another example) 编写的。如果可能,我希望避免依赖该库。
上面的查询可以用表达式和相关方法编写吗?
我知道如何使用 ParameterExpressions MemberExpressions 和 Expression.Lambda() 构造基本的 lambda 表达式,例如 foo => foo.Foo_Id,但是如何构造 (x,y) => new { Foo = x, Bars = y })?能够构造必要的参数来创建两个调用?
MethodCallExpression groupJoinCall =
Expression.Call(
typeof(Queryable),
"GroupJoin",
new Type[] {
typeof(Customers),
typeof(Purchases),
outerSelectorLambda.Body.Type,
resultsSelectorLambda.Body.Type
},
c.Expression,
p.Expression,
Expression.Quote(outerSelectorLambda),
Expression.Quote(innerSelectorLambda),
Expression.Quote(resultsSelectorLambda)
);
MethodCallExpression selectManyCall =
Expression.Call(typeof(Queryable),
"SelectMany", new Type[] {
groupJoinCall.ElementType,
resultType,
resultsSelectorLambda.Body.Type
}, groupJoinCall.Expression, Expression.Quote(lambda),
Expression.Quote(resultsSelectorLambda)));
最终,我需要创建一个可重复的过程,它将 join n Bars 留给 Foo。因为我们有一个垂直数据结构,所以需要一个左连接查询来返回表示为 Bars 的内容,以允许用户对 Foo 进行排序。要求是允许用户按 10 个条进行排序,但我不希望他们使用超过三个。我尝试编写一个进程,将上面第一个块中的代码最多链接 10 次,但是一旦我通过了 5 Visual Studio 2012 开始变慢并且大约 7 它被锁定。
因此,我现在正在尝试编写一个方法,该方法返回 selectManyCall 并根据用户的请求多次递归调用自身。
根据下面在 LinqPad 中工作的查询,需要重复的过程只需要手动处理 Expression 对象中的透明标识符。查询 sorts 返回按 Bars 排序的 Foos(在本例中为 3 个 Bars)。
附注。这个过程在 OrderBy 委托中进行连接要容易得多,但是,它产生的查询包括 T-SQL“OUTER APPLY”,Oracle 不支持这是必需的。
对于如何将投影写入匿名类型或任何其他开箱即用的想法,我很感激。谢谢。
var q = Foos
.GroupJoin (
Bars,
g => g.FooID,
sv => sv.FooID,
(g, v) =>
new
{
g = g,
v = v
}
)
.SelectMany (
s => s.v.DefaultIfEmpty (),
(s, v) =>
new
{
s = s,
v = v
}
)
.GroupJoin (
Bars,
g => g.s.g.FooID,
sv => sv.FooID,
(g, v) =>
new
{
g = g,
v = v
}
)
.SelectMany (
s => s.v.DefaultIfEmpty (),
(s, v) =>
new
{
s = s,
v = v
}
)
.GroupJoin (
Bars,
g => g.s.g.s.g.FooID,
sv => sv.FooID,
(g, v) =>
new
{
g = g,
v = v
}
)
.SelectMany (
s => s.v.DefaultIfEmpty (),
(s, v) =>
new
{
s = s,
v = v
}
)
.OrderBy (a => a.s.g.s.g.v.Text)
.ThenBy (a => a.s.g.v.Text)
.ThenByDescending (a => a.v.Date)
.Select (a => a.s.g.s.g.s.g);
【问题讨论】:
标签: entity-framework lambda left-join expression-trees linq-expressions