下面的代码块回答了这个问题:“如何使用 linq 扩展方法执行左外连接? ”
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? 我发现的所有示例都是使用 DynamicExpressions 将字符串转换为 lambdas 编写的(另一个示例)。如果可能的话,我想避免依赖该库。
上面的查询可以用表达式和相关方法编写吗?
我知道如何构造基本的 lambda 表达式,例如foo => foo.Foo_Id
使用 ParameterExpressions MemberExpressions 和 Expression.Lambda() ,但是你如何构造(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);