萬事不要操之過急,循序漸進就好。
在sql中我們會用到子查詢來進行復雜一些的查詢工作,在linq中同樣可以使用子查詢,不過如果是連接數據庫的話使用子查詢會只連接一次數據庫進行查詢,而如果是內存中的數據,則使用子查詢會效率低下,每次迭代返回至時都會執行子查詢,那麼就應該將子查詢分離出來。
在linq的方法語法中,子查詢包含在父查詢的lambda表達式中,即都要寫在匿名方法中, 查詢表達式 除了from字句不能使用子查詢 其他都可以使用子查詢
以下內容來自博客園
在創建一個複雜的查詢時,通常我們需要用到子查詢。相信大家都記得SQL查詢裏的子查詢,在創建LINQ查詢時也是如此。在LINQ中,對於方法語法,一個子查詢包含在另外一個查詢的lambda表達式中,對於查詢表達式語法來講,所有不是from子句中引用的查詢都是子查詢。
下面的查詢使用子查詢來對last name進行排序,語句中的n.Split().Last()就是一個子查詢:
string[] names = { "David Tim", "Tony Sin", "Rager Witers" };
IEnumerable<string> query = names.OrderBy(n => n.Split().Last());
子查詢的作用域限定在當前的lambda表達式中,並且可以引用外部lambda表達式的參數(查詢表達式的範圍變量)。
下面的查詢獲取所有長度最短的名字(注意:可能有多個):
static void TestSubQuery()
{
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
//獲取所有長度最短的名字(注意:可能有多個)
IEnumerable<string> outQuery = names
.Where(n => n.Length == names.OrderBy(n2 => n2.Length)
.Select(n2 => n2.Length).First()); // Tom, Jay"
// 與上面方法語法等價的查詢表達式
IEnumerable<string> outQuery2 =
from n in names
where n.Length ==(from n2 in names orderby n2.Length select n2.Length).First()
select n;
// 我們可以使用Min查詢運算符來簡化
IEnumerable<string> outQuery2 =
from n in names
where n.Length == names.Min(n2 => n2.Length)
select n;
}
因爲外部範圍變量在子查詢的作用域內,所以我們不能再次使用n作爲內部查詢的範圍變量。
一個子查詢在包含它的lambda表達式執行時被執行,這意味着子查詢的執行取決於外部查詢。需要注意的是:本地查詢(LINQ to Objects)和解釋查詢(LIQN to SQL)對於子查詢的處理方式是不一樣的。對於本地查詢,對於外部查詢的每一次循環,子查詢都會被重新執行一次。在稍後“解釋查詢”一篇中, 我們會看到,外部查詢和子查詢是作爲一個單元進行處理的,這樣,只需一次到遠程數據源(如數據庫)的連接。所以上面的例子對於一個數據庫查詢來說非常適合,但對於一個內存中的集合來說卻效率低下,這時我們可以把子查詢分離出來對讓它只執行一次(這樣它不再是一個子查詢)。
int shortest = names.Min(n => n.Length);
IEnumerable<string> query = from n in names
where n.Length == shortest
select n;
在延遲執行一篇中,我們說到元素和集合運算符如First和Count會讓一個查詢立即執行。但對一個子查詢來說,即使是元素和集合運算符也不會改變外部查詢延遲執行的特性。這是因爲,不管是對本地查詢還是通過表達式樹訪問的解釋查詢,子查詢是間接調用的。