的代碼塊回答了這個問題:「How do you perform a left outer join using linq extension methods?」如何使用MethodCallExpressions編寫左外連接?下面
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});
怎麼寫這個羣組加入和作爲的SelectMany MethodCallExpressions?我發現的All of the examples是使用DynamicExpressions將字符串轉換爲lambdas(another example)編寫的。如果可能,我喜歡避免依賴該庫。
上面的查詢可以使用表達式和相關方法編寫嗎?
我知道如何使用ParameterExpressions MemberExpressions和Expression.Lambda()構造像foo => foo.Foo_Id
這樣的基本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)));
最終,我需要創建一個可重複的過程,將n連接到Foo。因爲我們有一個垂直數據結構,所以需要一個左連接的查詢來返回表示爲Bars的內容,以允許用戶對Foo進行排序。要求是允許用戶按10條排序,但我不指望它們使用超過三條。我試圖編寫一個過程,在上面的第一個塊中鏈接代碼達10次,但是一旦我通過了,Visual Studio 2012開始減慢速度,大約7秒鎖定它。
因此,我現在正在嘗試編寫一個方法,該方法返回selectManyCall並按照用戶請求的次數遞歸調用自身。
根據下面的查詢在LinqPad中的工作,需要重複的過程只需要手動處理Expression對象中的透明標識符。查詢排序返回按條排序的Foos(在這種情況下爲3條)。
附註。這個過程在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);
謝謝傑夫。我已經在我的問題中添加了一些細節,以解釋爲什麼我迄今尚未預測到已定義的類型,並最終達到了我想要完成的目標。我不熟悉在dummyType中實現的屬性的「默認」使用。我會試試看。你認爲這可以實現使用像Dummy這樣的定義類型嗎?我非常感謝你的觀點和反饋。 – cResults 2013-02-24 14:44:32
而不是使用你自己定義的類型,也許你可以嘗試使用一個元組?只要你使用構造函數來創建它們(而不是'Tuple.Create()'工廠),我認爲你的LINQ提供者會支持它。只要虛擬類型只是簡單的對象,它們只保存值,虛擬類型就會工作。由於大多數(如果不是全部的話)供應商不會支持,所以添加任何其他方法都不行。 – 2013-02-24 16:32:39
我讀過關於元組,但從未使用。投影到'tuple.Item1 = g,tuple.Item2 = v'?如果這是正確的,我將如何在後續項目和OrderBy子句中訪問它們? – cResults 2013-02-25 22:45:58