查詢是從數據源擷取數據的表達式。 查詢通常以特製化查詢語言表示,例如關係資料庫 SQL 和 XML 的 XQuery。 因此,開發人員必須針對所查詢的每個數據源或數據格式,學習新的查詢語言。 Language-Integrated 查詢 (LINQ) 提供更簡單、一致的模型,可用於處理各種數據源和格式的數據。 在 LINQ 查詢中,您一律會使用程式物件。
LINQ 查詢作業包含三個動作:取得數據源或來源、建立查詢,以及執行查詢。
您可以透過LINQ查詢實作泛型介面的 IEnumerable<T> 數據源。 呼叫AsEnumerable在DataTable上會傳回一個實作泛型IEnumerable<T>介面的物件,這個介面作為LINQ to DataSet查詢的資料來源。
在查詢中,您可以指定您想要從數據源擷取的資訊。 查詢也可以指定該資訊在傳回之前應該如何排序、分組和成形。 在 LINQ 中,查詢會儲存在變數中。 如果查詢是設計來傳回值序列,則查詢變數本身必須是可列舉的類型。 此查詢變數不會採取任何動作,而且不會傳回任何數據;它只會儲存查詢資訊。 建立查詢之後,您必須執行該查詢以擷取任何數據。
在傳回值序列的查詢中,查詢變數本身絕不會保存查詢結果,而且只會儲存查詢命令。 查詢的執行會延後,直到在foreach或For Each迴圈中逐一查看查詢變數為止。 這稱為 延後執行;也就是說,查詢執行會在建構查詢之後一段時間發生。 這表示您可以視需要執行查詢的頻率。 例如,當您有其他應用程式正在更新的資料庫時,這會很有用。 在您的應用程式中,您可以建立查詢來擷取最新資訊,並重複執行查詢,每次傳回更新的資訊。
相較於會傳回值序列的延後查詢,會立即執行傳回單一值的查詢。 單一查詢的一些範例包括 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
Method-Based 查詢語法
制定 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: {productInfo.ProductName} Product number: {productInfo.ProductNumber} List price: ${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