LINQ to DataSet 中的查詢

更新: November 2007

查詢是指從資料來源中擷取資料的運算式。查詢通常會以特定的查詢語言來表示,例如 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) 中反覆查看查詢變數為止。這就稱為「延後執行」。也就是說,查詢執行會在建構查詢之後的某個時間點進行。這表示,您可以依照想要的頻率來執行查詢。例如,當您擁有一個正由其他應用程式更新的資料庫時,這就很有用。您可以在應用程式中建立擷取最新資訊的查詢,然後重複執行此查詢,以便每次都傳回更新的資訊。

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

查詢

您可以用兩種不同的語法來編寫 LINQ to DataSet 查詢:查詢運算式語法和以方法為基礎的查詢語法。

查詢運算式語法

查詢運算式是宣告式查詢語法。這種語法可讓開發人員使用類似 SQL 的格式,在 C# 或 Visual Basic 中撰寫查詢。透過使用查詢運算式語法,您就可以利用最少的程式碼,針對資料來源執行同樣複雜的篩選、排序和分組作業。如需詳細資訊,請參閱 LINQ 查詢運算式 (C# 程式設計手冊)基本查詢作業 (Visual Basic)

查詢運算式語法是 C# 3.0 和 Visual Basic 2008 中的新增功能。不過,.NET Framework Common Language Runtime (CLR) 無法讀取查詢運算式語法本身。因此,在編譯時期,查詢運算式會轉譯成 CLR 可瞭解的內容:方法呼叫。這些方法稱為「標準查詢運算子」。身為開發人員,您可以選擇使用方法語法來直接呼叫它們,而非使用查詢語法。如需詳細資訊,請參閱查詢語法與方法語法的比較 (LINQ)。如需如何使用標準查詢運算子的詳細資訊,請參閱 LINQ 程式設計手冊概論

下列範例會使用 Select 來傳回 Product 資料表中的所有資料列,並顯示產品名稱。

' 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
// 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"));
}

以方法為基礎的查詢語法

另一種編寫 LINQ to DataSet 查詢的方式是使用以方法為基礎的查詢。以方法為基礎的查詢語法是對 LINQ 運算子方法之直接方法呼叫的序列,並傳遞 Lambda 運算式當做參數。如需詳細資訊,請參閱 Lambda 運算式 (C# 程式設計手冊)

這則範例會使用 Select 來傳回 Product 資料表中的所有資料列,並顯示產品名稱。

' 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
// 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);
}

撰寫查詢

如本主題先前所述,當查詢設計為傳回值的序列時,查詢變數本身只會儲存查詢命令。如果查詢沒有包含將導致立即執行的方法,查詢的實際執行將延後,直到您在 foreach 或 For Each 迴圈中反覆查看查詢變數為止。延後執行可結合多個查詢或擴充單一查詢。擴充單一查詢時,它會修改成包含新的作業,而且最終的執行將反映這些變更。在下列範例中,第一個查詢會傳回所有產品。第二個查詢會使用 Where 來擴充第一個查詢,以便傳回大小為 "L" 的所有產品:

' 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

// 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"));
}


在您已經執行過查詢之後,便無法撰寫其他查詢,而且所有後續的查詢都將使用記憶體中 LINQ 運算子。當您在 foreach 或 For Each 陳述式中反覆查看查詢變數,或呼叫導致立即執行的其中一個 LINQ 轉換運算子時,將會進行查詢執行。這些運算子包括:ToList<TSource>ToArray<TSource>ToLookupToDictionary

在下列範例中,第一個查詢會傳回所有產品,並依照標價排序。ToArray<TSource> 方法是用來強制立即執行查詢:

' 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
// 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"));
}

請參閱

概念

查詢 DataSet (LINQ to DataSet)

其他資源

程式設計手冊 (LINQ to DataSet)

使用 C# 撰寫 LINQ 入門

使用 Visual Basic 撰寫 LINQ 入門