次の方法で共有


LINQ to DataSet でのクエリ

更新 : November 2007

クエリは、データ ソースからデータを取得する式です。一般に、クエリは専用のクエリ言語で表現されます。たとえば、リレーショナル データベースであれば SQL、XML であれば XQuery が使用されます。そのため、開発者はクエリの対象となるデータ ソースやデータ形式ごとに新しいクエリ言語を習得する必要があります。統合言語クエリ (LINQ: Language-Integrated Query) は、データ ソースや形式の違いを意識することなくデータを扱うことのできる、より簡素化された一貫したモデルを提供します。LINQ クエリでは、常にプログラミング オブジェクトを操作することになります。

LINQ のクエリ操作は、データ ソースを取得し、クエリを作成して、クエリを実行するという 3 つのアクションから成ります。

LINQ を介したクエリは、IEnumerable<T> ジェネリック インターフェイスを実装するデータ ソースに対して行うことができます。DataTableAsEnumerable を呼び出すと、ジェネリック IEnumerable<T> インターフェイスを実装するオブジェクトが返されます。このオブジェクトが、LINQ to DataSet クエリのデータ ソースとして機能します。

クエリでは、データ ソースから取得する情報を正確に指定できます。また、並べ替え、グループ化、整形方法を指定して情報を取得することもできます。LINQ では、クエリが変数に格納されます。一連の値を返すようにクエリを設計する場合、クエリ変数そのものが列挙可能な型であることが必要です。このクエリ変数は、クエリの情報を保存するだけで、なんらかのアクションを実行したり、データを返したりすることはありません。クエリを作成した後、データを取得するには、そのクエリを実行する必要があります。

一連の値を返すクエリでは、クエリ変数そのものはクエリ結果を保持しません。クエリ変数には、クエリのコマンドが格納されるだけです。クエリ変数が foreach ループまたは For Each ループで反復処理されるまで、クエリは実行されません。これを遅延実行と呼びます。つまり、作成されたクエリはすぐには実行されません。これは、任意のタイミングでクエリを実行できるということを意味します。これは、たとえば他のアプリケーションによって更新されるデータベースがある場合に便利です。アプリケーションで、最新情報を取得するクエリを作成し、それを繰り返し実行することにより、更新のたびに最新の情報を取得できます。

遅延実行によって一連の値を返すクエリとは対照的に、シングルトン値を返すクエリは直ちに実行されます。シングルトン クエリの例としては、CountMaxAverageFirst があります。これらのシングルトン クエリは、結果を計算するためにはクエリ結果が必要であるため、直ちに実行されます。たとえば、クエリ結果の平均を求めるためには、クエリを実行して、平均関数に入力データを与える必要があります。シングルトン値を生成しないクエリでも、ToList<TSource> メソッドまたは ToArray<TSource> メソッドを使用することによって、即時実行を強制できます。即時実行を強制するこの手法は、クエリの結果をキャッシュする場合などに使用すると効果的です。クエリの遅延実行と即時実行の詳細については、「LINQ の概要」を参照してください。

クエリ

LINQ to DataSet クエリは、クエリ式の構文とメソッド ベースのクエリ構文という 2 とおりの構文を使って作成できます。

クエリ式の構文

クエリ式は宣言型のクエリ構文です。開発者は SQL に似た構文形式を C# または Visual Basic で用いてクエリを作成できます。クエリ式の構文を使用することにより、フィルタ、並べ替え、グループ化など、データ ソースに対するきわめて複雑な処理を最小限のコードで実行できます。詳細については、「LINQ クエリ式 (C# プログラミング ガイド)」および「基本的なクエリ操作 (Visual Basic)」を参照してください。

クエリ式の構文は、C# 3.0 および Visual Basic 2008 で新たに導入されたものです。ただし、.NET Framework の共通言語ランタイム (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 クエリを作成するもう 1 つの方法として、メソッド ベースのクエリがあります。メソッド ベースのクエリ構文は、LINQ の演算子メソッドを、ラムダ式をパラメータとして直接順次呼び出すものです。詳細については、「ラムダ式 (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 ループでクエリ変数を反復処理するまで、実際にはクエリは実行されません。遅延実行により、複数のクエリを組み合わせたり、クエリを拡張したりすることが可能となります。クエリを拡張して新しい操作を追加すると、その変更が最終的な実行時に反映されます。次の例の最初のクエリでは、すべての製品が返されます。2 つ目のクエリでは、サイズが "L" のすべての製品を返すように、Where を使って 1 つ目のクエリを拡張しています。

' 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 の概要