分享方式:


LINQ to DataSet 中的查詢

查詢是指從資料來源中擷取資料的運算式。 查詢通常會以特定的查詢語言來表示,例如 SQL 用於關聯式資料庫,而 XQuery 用於 XML。 因此,開發人員必須針對他們所查詢的每種資料來源或資料格式,學習新的查詢語言。 Language-Integrated Query (LINQ) 提供了一種較簡單且一致的模型,可處理各種資料來源和格式的資料。 在 LINQ 查詢中,您一定會使用程式設計物件。

LINQ 查詢作業由三個動作構成:取得資料來源、建立查詢和執行查詢。

您可以透過 LINQ 查詢實作 IEnumerable<T> 泛型介面的資料來源。 對 DataTable 呼叫 AsEnumerable 會傳回實作泛型 IEnumerable<T> 介面的物件,而此物件會當做 LINQ to DataSet 查詢的資料來源。

在此查詢中,您可以精確地指定想要從資料來源中擷取的資訊。 此外,查詢也可以指定該項資訊傳回之前應該如何排序、分組和成形。 在 LINQ 中,查詢會儲存在變數內。 如果查詢設計成傳回值的序列 (Sequence),查詢變數本身就必須是可列舉的型別。 這個查詢變數不會採取任何動作,也不會傳回任何資料。它只會儲存查詢資訊。 在您建立查詢之後,必須執行該查詢以便擷取任何資料。

在傳回值序列的查詢中,查詢變數本身絕不會保存查詢結果,只會儲存查詢命令而已。 查詢的執行會延後,直到在 foreachFor Each 迴圈 (Loop) 中反覆查看查詢變數為止。 這稱為「延後執行」;也就是說,查詢執行會在建構查詢之後的某個時間點進行。 這表示,您可以依照想要的頻率來執行查詢。 例如,當您擁有一個正由其他應用程式更新的資料庫時,這就很有用。 您可以在應用程式中建立擷取最新資訊的查詢,然後重複執行此查詢,以便每次都傳回更新的資訊。

相較於傳回值序列的延後查詢,傳回單一子句值的查詢會立即執行。 單一子句查詢的某些範例包括 CountMaxAverageFirst。 這些查詢會立即執行,因為系統需要查詢結果來計算單一子句結果。 例如,若要尋找查詢結果的平均值,您必須執行查詢,如此平均函式才有輸入資料可處理。 此外,您也可以針對查詢使用 ToListToArray 方法,強制立即執行不會產生單一子句值的查詢。 當您想要快取查詢的結果時,這些強制立即執行的技巧就很有用。

查詢

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

撰寫查詢

如本主題先前所述,當查詢設計為傳回值的序列時,查詢變數本身只會儲存查詢命令。 如果查詢沒有包含將導致立即執行的方法,查詢的實際執行將延後,直到您在 foreachFor 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 運算子。 當您在 foreachFor Each 陳述式中逐一查看查詢變數,或呼叫導致立即執行的其中一個 LINQ 轉換運算子時,將會進行查詢執行。 這些運算子包括:ToListToArrayToLookupToDictionary

在下列範例中,第一個查詢會傳回所有產品,並依照標價排序。 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

另請參閱