DotNet LINQ 是什麼

LINQ(Language Integrated Query),在 .Net Framework 3.5 之後發布的技術,讀作 “link”,不是 “另Q”。照中文翻譯就是語言整合查詢,大概就是這個意思,雖然背後有很多實作概念,但目前還沒有要提到。

使用關聯式資料庫儲存資料必然使用 SQL 語法查詢,LINQ 這項技術能夠讓你在程式語言中直接使用類似 SQL 語法來查詢、操作、聚合資料等。很古早時候要從一個陣列中找到符合條件的程式寫起來很辛苦,舉個例子,找到數值大於 5的值有哪些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var data = new List<int>() {1,3,5,7,9};
var greaterThan5Data = new List<int>();

foreach (var item in data)
{
if (item > 5)
{
greaterThan5Data.Add(item);
}
}

foreach (var item in greaterThan5Data)
{
Console.WriteLine(item);
}

當然,上述例子是比較誇張的,但事後回想,在 LINQ 問世前,或者工作經驗比較不足時,確實也都是類似的做法。

1
2
3
4
5
6
7
8
9
var data = new List<int>() {1,3,5,7,9};

var greaterThan5Data = from item in data
where item > 5;

foreach (var item in greaterThan5Data)
{
Console.WriteLine(item);
}

這樣是不是簡潔很多了?
不是!還可以再簡潔!

C# 這個語言進步速度飛快,扣除 語法糖(syntax sugar) 之外,很多技術都在持續演進中。上面這個語法我們稱為 查詢表示式(Query Expression),在多一點的操作後就會變得閱讀性不佳(當然,多看總會習慣的),不過實作上更多的是使用另一種表示方法,Lambda Expression

1
2
3
4
5
6
7
8
var data = new List<int>() {1,3,5,7,9};

var greaterThan5Data = data.Where(item => item > 5);

foreach (var item in greaterThan5Data)
{
Console.WriteLine(item);
}

這兩者之間的差異就是哪個格式你看的習慣,或者團隊習慣使用哪一種,編譯後都是長得一樣的,所以也沒有存在效能上差異,除此之外 lamda 表示式還能夠延伸出更多使用的功能,在後面會演示一下。

以我個人的經驗來說,lamda 表示式是更方便排版與直觀上的閱讀。在設計上傾向讓這些 SQL 類型的過濾都放在資料庫做,一來這就是資料庫強項,二來減少資料傳輸 IO,把資料減少絕對是首選。

程式與資料庫效能這之間牽涉到很多東西,像是 entity framework, SQL/SP (甚至獨有的 T-SQL)等比較,就不在這邊討論,這很仰賴團隊資源、技術力、人員組成與協作,絕對無法找到最佳解,只有最適解


接下來的範例統一會使用 lambda expression….

延遲執行(載入)特性

LINQ 另一個特性就是帶來了延遲載入,也就是等到需要使用時,才會開始執行。這樣聽起來有點抽象,讓我們直接看例子:

我們同樣使用上面的範例,且這個範例就已經在使用延遲載入的特性囉!

宣告 greaterThan5Data 後,與 foreach 之間我們再加入幾個數值 13, 15

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var data = new List<int> {1,3,5,7,9};

var greaterThan5Data = data.Where(item => item > 5);

data.Add(13);
data.Add(15);

foreach (var item in greaterThan5Data)
{
Console.WriteLine(item);
}

output:
7
9
13
15

從上面的例子可以看到在使用 LINQ 語法時,並沒有真正的去遍尋 data 整個 List,中間還插入了 2 個數值,直到 foreach 執行時,才去做判斷 item > 5 的確認。

小變化

可以思考一下這段程式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var data = new List<int> {1,3,5,7,9};

var greaterThan5Data = data
.Select(item =>
{
if (item > 5)
{
Console.WriteLine($"Inner: {item}");
}
return item;
});

foreach (var item in greaterThan5Data)
{
Console.WriteLine($"Outer:{item}");
}

Output:

Outer:1
Outer:3
Outer:5
Inner: 7
Outer:7
Inner: 9
Outer:9
  1. 輸出為什麼是這樣?
  2. 什麼情境下會需要這樣使用?

延遲載入的優勢在於:只有需要使用到時,才會消耗 CPU 執行與 記憶體 的佔據

有使用 IDE 開發的,通常也會顯示 LINQ 的型別,通常是 IEnumerable<T>

如果不想要延遲載入怎麼辦

有些邏輯可能在 LINQ 語法不好寫,或是經驗不足,必須馬上取得結果的話,可以透過呼叫取得值的方法,像是

  • .First()
  • .Average()
  • .Max()

或是

  • .ToArray()
  • .ToList()

觀念上就是只要取得結果的,就會立刻執行。


LINQ 實際應用非常廣泛,甚至很多人會連為什麼這樣用,或者用到什麼技術都不見得達得上來,建議也可以深入了解一下。

  • 作者: MingYi Chou
  • 版權聲明: 轉載不用問,但請註明出處!本網誌均採用 BY-NC-SA 許可協議。