LINQ to DataSet 中的查詢
查詢是指從資料來源中擷取資料的運算式。 查詢通常會以特定的查詢語言來表示,例如 SQL 用於關聯式資料庫,而 XQuery 用於 XML。 因此,開發人員必須針對他們所查詢的每種資料來源或資料格式,學習新的查詢語言。 Language-Integrated Query (LINQ) 提供了一種較簡單且一致的模型,可處理各種資料來源和格式的資料。 在 LINQ 查詢中,您一定會使用程式設計物件。
LINQ 查詢作業由三個動作構成:取得資料來源、建立查詢和執行查詢。
您可以透過 LINQ 查詢實作 IEnumerable<T> 泛型介面的資料來源。 對 DataTable 呼叫 AsEnumerable 會傳回實作泛型 IEnumerable<T> 介面的物件,而此物件會當做 LINQ to DataSet 查詢的資料來源。
在此查詢中,您可以精確地指定想要從資料來源中擷取的資訊。 此外,查詢也可以指定該項資訊傳回之前應該如何排序、分組和成形。 在 LINQ 中,查詢會儲存在變數內。 如果查詢設計成傳回值的序列 (Sequence),查詢變數本身就必須是可列舉的型別。 這個查詢變數不會採取任何動作,也不會傳回任何資料。它只會儲存查詢資訊。 在您建立查詢之後,必須執行該查詢以便擷取任何資料。
在傳回值序列的查詢中,查詢變數本身絕不會保存查詢結果,只會儲存查詢命令而已。 查詢的執行會延後,直到在 foreach
或 For Each
迴圈 (Loop) 中反覆查看查詢變數為止。 這稱為「延後執行」;也就是說,查詢執行會在建構查詢之後的某個時間點進行。 這表示,您可以依照想要的頻率來執行查詢。 例如,當您擁有一個正由其他應用程式更新的資料庫時,這就很有用。 您可以在應用程式中建立擷取最新資訊的查詢,然後重複執行此查詢,以便每次都傳回更新的資訊。
相較於傳回值序列的延後查詢,傳回單一子句值的查詢會立即執行。 單一子句查詢的某些範例包括 Count、Max、Average 和 First。 這些查詢會立即執行,因為系統需要查詢結果來計算單一子句結果。 例如,若要尋找查詢結果的平均值,您必須執行查詢,如此平均函式才有輸入資料可處理。 此外,您也可以針對查詢使用 ToList 或 ToArray 方法,強制立即執行不會產生單一子句值的查詢。 當您想要快取查詢的結果時,這些強制立即執行的技巧就很有用。
查詢
LINQ to DataSet 查詢可以使用兩個不同的語法來撰寫:查詢運算式語法和方法型查詢語法。
查詢運算式語法
查詢運算式是宣告式查詢語法。 這種語法可讓開發人員使用類似 SQL 的格式,在 C# 或 Visual Basic 中撰寫查詢。 透過使用查詢運算式語法,您就可以利用最少的程式碼,針對資料來源執行同樣複雜的篩選、排序和分組作業。 如需詳細資訊,請參閱 LINQ 查詢運算式和基本查詢作業 (Visual Basic)。
.NET Framework Common Language Runtime (CLR) 無法讀取查詢運算式語法本身。 因此,在編譯期間,查詢運算式會轉譯為 CLR 可以了解的項目:即方法呼叫。 這些方法稱為「標準查詢運算子」。 身為開發人員,您可以選擇使用方法語法來直接呼叫它們,而非使用查詢語法。 如需詳細資訊,請參閱 LINQ 中的查詢語法及方法語法。 如需標準查詢運算子的詳細資訊,請參閱標準查詢運算子概觀。
下列範例會使用 Select 來傳回 Product
資料表中的所有資料列,並顯示產品名稱。
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
select product;
Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim products As DataTable = ds.Tables("Product")
Dim query = From product In products.AsEnumerable() _
Select product
Console.WriteLine("Product Names:")
For Each p In query
Console.WriteLine(p.Field(Of String)("Name"))
Next
以方法為基礎的查詢語法
另一種編寫 LINQ to DataSet 查詢的方式是使用方法型查詢。 以方法為基礎的查詢語法是對 LINQ 運算子方法之直接方法呼叫的序列,並傳遞 Lambda 運算式當做參數。 如需詳細資訊,請參閱 Lambda 運算式。
這則範例會使用 Select 來傳回 Product
資料表中的所有資料列,並顯示產品名稱。
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
var query = products.AsEnumerable().
Select(product => new
{
ProductName = product.Field<string>("Name"),
ProductNumber = product.Field<string>("ProductNumber"),
Price = product.Field<decimal>("ListPrice")
});
Console.WriteLine("Product Info:");
foreach (var productInfo in query)
{
Console.WriteLine("Product name: {0} Product number: {1} List price: ${2} ",
productInfo.ProductName, productInfo.ProductNumber, productInfo.Price);
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim products As DataTable = ds.Tables("Product")
Dim query = products.AsEnumerable() _
.Select(Function(product As DataRow) New With _
{ _
.ProductName = product.Field(Of String)("Name"), _
.ProductNumber = product.Field(Of String)("ProductNumber"), _
.Price = product.Field(Of Decimal)("ListPrice") _
})
Console.WriteLine("Product Info:")
For Each product In query
Console.Write("Product name: " & product.ProductName)
Console.Write("Product number: " & product.ProductNumber)
Console.WriteLine("List price: $ " & product.Price)
Next
撰寫查詢
如本主題先前所述,當查詢設計為傳回值的序列時,查詢變數本身只會儲存查詢命令。 如果查詢沒有包含將導致立即執行的方法,查詢的實際執行將延後,直到您在 foreach
或 For Each
迴圈中反覆查看查詢變數為止。 延後執行可結合多個查詢或擴充單一查詢。 擴充單一查詢時,它會修改成包含新的作業,而且最終的執行將反映這些變更。 在下列範例中,第一個查詢會傳回所有產品。 第二個查詢會使用 Where
來擴充第一個查詢,以便傳回大小為 "L" 的所有產品:
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> productsQuery =
from product in products.AsEnumerable()
select product;
IEnumerable<DataRow> largeProducts =
productsQuery.Where(p => p.Field<string>("Size") == "L");
Console.WriteLine("Products of size 'L':");
foreach (DataRow product in largeProducts)
{
Console.WriteLine(product.Field<string>("Name"));
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim products As DataTable = ds.Tables("Product")
Dim productsQuery = From product In products.AsEnumerable() _
Select product
Dim largeProducts = _
productsQuery.Where(Function(p) p.Field(Of String)("Size") = "L")
Console.WriteLine("Products of size 'L':")
For Each product In largeProducts
Console.WriteLine(product.Field(Of String)("Name"))
Next
在執行了查詢之後,就無法撰寫其他查詢,而且所有後續的查詢都將使用記憶體中 LINQ 運算子。 當您在 foreach
或 For Each
陳述式中逐一查看查詢變數,或呼叫導致立即執行的其中一個 LINQ 轉換運算子時,將會進行查詢執行。 這些運算子包括:ToList、ToArray、ToLookup 和 ToDictionary。
在下列範例中,第一個查詢會傳回所有產品,並依照標價排序。 ToArray 方法是用來強制立即執行查詢:
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
orderby product.Field<Decimal>("ListPrice") descending
select product;
// Force immediate execution of the query.
IEnumerable<DataRow> productsArray = query.ToArray();
Console.WriteLine("Every price from highest to lowest:");
foreach (DataRow prod in productsArray)
{
Console.WriteLine(prod.Field<Decimal>("ListPrice"));
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)
Dim products As DataTable = ds.Tables("Product")
Dim query = _
From product In products.AsEnumerable() _
Order By product.Field(Of Decimal)("ListPrice") Descending _
Select product
' Force immediate execution of the query.
Dim productsArray = query.ToArray()
Console.WriteLine("Every price From highest to lowest:")
For Each prod In productsArray
Console.WriteLine(prod.Field(Of Decimal)("ListPrice"))
Next