撰寫第一個 LINQ 查詢 (Visual Basic)
「查詢」是指從資料來源中擷取資料的運算式。 系統會以專用的查詢語言表示查詢。 針對各種資料來源類型開發不同的語言已有一段時間,例如用於關聯式資料庫的 SQL,以及用於 XML 的 XQuery。 這可讓應用程式開發人員了解每種支援的資料來源或資料格式的新查詢語言。
Language-Integrated Query (LINQ) 提供一致的查詢模型,以便處理各種資料來源和格式的資料,因此可簡化此情況。 在 LINQ 查詢中,您所處理的一定是物件。 您可使用相同基本程式碼編寫模式來查詢和轉換 XML 文件、SQL 資料庫、ADO.NET 資料集和實體、.NET Framework 集合和任何其他提供 LINQ 提供者來源和格式中的資料。 本文件說明建立和使用基本 LINQ 查詢的三個階段。
查詢作業的三個階段
LINQ 的查詢作業都包含三個不同的動作:
取得資料來源或來源。
建立查詢。
執行查詢。
在 LINQ 中,查詢的執行與建立查詢不同。 您不僅可透過建立查詢即可擷取任何資料。 本主題稍後會詳細討論這一點。
下列範例說明查詢作業的三個部分。 此範例會使用整數陣列做為方便的資料來源,以供示範所用。 不過,相同的概念也適用於其他資料來源。
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers
Where num Mod 2 = 0
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
輸出:
0 2 4 6
資料來源
由於先前範例中的資料來源為陣列,意味著其也支援泛型 IEnumerable<T> 介面。 這個事實可讓您使用陣列做為 LINQ 查詢的資料來源。 支援 IEnumerable<T> 或衍生介面的類型,例如泛型 IQueryable<T> 稱為可查詢的類型。
作為隱含可查詢類型,陣列無須進行修改或特殊處理,即可作為 LINQ 資料來源。 支援 IEnumerable<T> 的任何集合類型都相同,包括 .NET Framework 類別庫中的泛型 List<T>、Dictionary<TKey,TValue> 和其他類別。
如果來源資料尚未實作 IEnumerable<T>,則需要 LINQ 提供者,才能針對該資料來源實作標準查詢運算子的功能。 例如,LINQ to XML 處理會將 XML 文件載入可查詢 XElement 類型的工作,如下列範例所示。 如需標準查詢運算子的詳細資訊,請參閱標準查詢運算子概觀 (Visual Basic)。
' Create a data source from an XML document.
Dim contacts = XElement.Load("c:\myContactList.xml")
使用 LINQ to SQL 時,請先在設計階段以手動方式或使用 Visual Studio 中的 LINQ to SQL 工具,來建立物件關聯式對應。 您可針對物件撰寫查詢,LINQ to SQL 會在執行階段處理與資料庫之間的通訊。 在下列範例中,customers
代表資料庫中特定的資料表,而 Table<TEntity> 支援泛型 IQueryable<T>。
' Create a data source from a SQL table.
Dim db As New DataContext("C:\Northwind\Northwnd.mdf")
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)
如需如何建立特定資料來源類型的詳細資訊,請參閱各類 LINQ 提供者的文件。 (如需這些提供者的清單,請參閱 LINQ (Language-Integrated Query)。) 基本的規則很清楚:任何支援泛型 IEnumerable<T> 介面或所繼承介面的物件,皆可為 LINQ 資料來源。
注意
這些類型 (例如 ArrayList) 支援非泛型 IEnumerable 介面,也可作為 LINQ 資料來源。 如需使用 ArrayList 的範例,請參閱操作說明:使用 LINQ 查詢 ArrayList (Visual Basic)。
查詢
在此查詢中,您可以指定想要從資料來源中擷取的資訊。 您也可以選擇指定該資訊在傳回之前應該如何排序、分組或結構化。 為啟用查詢建立,Visual Basic 已將新的查詢語法併入語言中。
執行時,下列範例中的查詢會從整數陣列傳回所有偶數,numbers
。
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers
Where num Mod 2 = 0
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
此查詢運算式包含三個子句︰From
、Where
和 Select
。 基本查詢作業 (Visual Basic) 中討論每個查詢運算式子句的特定函式和用途。 如需詳細資訊,請參閱查詢。 請注意,在 LINQ 中,查詢定義通常會儲存在變數中,並在稍後執行。 查詢變數,例如 evensQuery
在上一個範例中,必須是可查詢的類型。 evensQuery
的類型為 IEnumerable(Of Integer)
,由編譯器使用本機類型推斷指派。
重要的是您要記住,查詢變數本身不會採取任何動作,而且不會傳回任何資料。 它只會儲存查詢定義。 在上一個範例中,此項目是執行查詢的 For Each
迴圈。
查詢執行
查詢執行會與建立查詢分開進行。 查詢建立會定義查詢,但會由不同的機制觸發本執行。 查詢一經定義便可執行 (「立即執行」),或者儲存定義以待稍後執行查詢 (「延後執行」)。
延後執行
典型的 LINQ 查詢與上一個範例 evensQuery
中定義的查詢類似。 此項目會建立查詢,但不會立即執行。 相反地,查詢定義會儲存在查詢變數 evensQuery
中。 您稍後會執行查詢,通常是使用 For Each
迴圈來傳回值序列,或套用標準查詢運算子,例如 Count
或 Max
。 此程序稱為「延後執行」。
' Query execution that results in a sequence of values.
For Each number In evensQuery
Console.Write(number & " ")
Next
' Query execution that results in a single value.
Dim evens = evensQuery.Count()
針對值序列,您可以使用 For Each
迴圈中的反覆項目變數來存取擷取的資料 (如上述範例中的 number
)。 因為查詢變數 evensQuery
會保存查詢定義,而不是查詢結果,所以您可以使用查詢變數多次執行查詢。 例如,您可以在您的應用程式中擁有會由個別應用程式持續更新的資料庫。 建立透過該資料庫擷取資料的查詢之後,您可以使用 For Each
迴圈重複執行查詢,每次均擷取最新的資料。
下列範例示範延後執行的運作方式。 使用 For Each
迴圈定義和執行 evensQuery2
之後,如先前的範例所示,資料來源 numbers
中的某些元素會變更。 然後第二個 evensQuery2
迴圈會再次執行 For Each
。 第二次的結果不同,因為 For Each
迴圈會使用 numbers
中的新值再次執行查詢。
Dim numberArray() = {0, 1, 2, 3, 4, 5, 6}
Dim evensQuery2 = From num In numberArray
Where num Mod 2 = 0
Select num
Console.WriteLine("Evens in original array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
' Change a few array elements.
numberArray(1) = 10
numberArray(4) = 22
numberArray(6) = 8
' Run the same query again.
Console.WriteLine(vbCrLf & "Evens in changed array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
輸出:
Evens in original array:
0 2 4 6
Evens in changed array:
0 10 2 22 8
立即執行
在延後執行的查詢中,查詢定義會儲存在查詢變數中,以供稍後執行。 在立即執行中,查詢會在定義時執行。 當您套用需要存取查詢結果個別元素的方法時,就會觸發執行。 直接執行通常是使用其中一個傳回單一值的標準查詢運算子來強制執行。 例如,Count
、Max
、Average
和 First
。 這些標準查詢運算子會在套用查詢後立即執行查詢,以便計算並傳回單一結果。 如需傳回單一值之標準查詢運算子的詳細資訊,請參閱匯總作業、元素作業和數量詞作業。
下列查詢會傳回整數陣列中的偶數計數。 查詢定義不會儲存,而且 numEvens
是簡單的 Integer
。
Dim numEvens = (From num In numbers
Where num Mod 2 = 0
Select num).Count()
您可以使用 Aggregate
方法達到相同的結果。
Dim numEvensAgg = Aggregate num In numbers
Where num Mod 2 = 0
Select num
Into Count()
您也可以在查詢 (立即執行) 或查詢變數 (延後執行) 上呼叫 ToList
或 ToArray
來強制執行,如下列程式碼所示。
' Immediate execution.
Dim evensList = (From num In numbers
Where num Mod 2 = 0
Select num).ToList()
' Deferred execution.
Dim evensQuery3 = From num In numbers
Where num Mod 2 = 0
Select num
' . . .
Dim evensArray = evensQuery3.ToArray()
在先前的範例中,evensQuery3
是查詢變數,但 evensList
是清單,而 evensArray
是陣列。
當您想要立即執行查詢並在單一集合物件中快取結果的情況下,使用 ToList
或 ToArray
進行強制立即執行特別有用。 如需這些方法的詳細資訊,請參閱轉換資料類型。
您也可以使用 IEnumerable
方法執行查詢,例如 IEnumerable.GetEnumerator 方法。