Visual Basic における LINQ の概要

統合言語クエリ (LINQ) は、Visual Basic にクエリ機能を追加します。この単純かつ強力な機能を使用して、あらゆる種類のデータを操作できます。 処理の対象であるデータベースにクエリを送信したり、検索するデータの種類ごとに異なるクエリ構文を使用したりする代わりに、LINQ では、Visual Basic 言語の一部としてのクエリを採用しています。 LINQ では、データの型に関係なく、統一された構文を使用します。

LINQ を使用すると、SQL Server データベース、XML、インメモリ配列、インメモリ コレクション、ADO.NET データセットなど、LINQ をサポートするリモートまたはローカルのデータ ソースのデータに対してクエリを実行できます。 これらはすべて、共通 Visual Basic 言語要素を使用して実行できます。 クエリは Visual Basic 言語で記述されるので、クエリ結果は、厳密に型指定されたオブジェクトとして返されます。 これらのオブジェクトは IntelliSense をサポートするので、コードの記述時間を短縮でき、さらに、クエリに含まれるエラーを実行時ではなくコンパイル時に把握できます。 LINQ クエリは、結果を絞り込むための追加クエリのソースとして使用できます。 クエリ結果をユーザーが簡単に表示および変更できるように、コントロールにバインディングすることもできます。

たとえば、次のコード例は、コレクションから顧客リストを返し、住所に基づいて顧客をグループ化する LINQ クエリを示しています。

' Obtain a list of customers.
Dim customers As List(Of Customer) = GetCustomers()

' Return customers that are grouped based on country.
Dim countries = From cust In customers
                Order By cust.Country, cust.City
                Group By CountryName = cust.Country
                Into CustomersInCountry = Group, Count()
                Order By CountryName

' Output the results.
For Each country In countries
    Debug.WriteLine(country.CountryName & " count=" & country.Count)

    For Each customer In country.CustomersInCountry
        Debug.WriteLine("   " & customer.CompanyName & "  " & customer.City)
    Next
Next

' Output:
'   Canada count=2
'      Contoso, Ltd  Halifax
'      Fabrikam, Inc.  Vancouver
'   United States count=1
'      Margie's Travel  Redmond

例の実行

概要と「LINQ クエリの構造」セクションの例を実行するには、次のコードを含めます。これにより、顧客と注文の一覧が返されます。

' Return a list of customers.
Private Function GetCustomers() As List(Of Customer)
    Return New List(Of Customer) From
        {
            New Customer With {.CustomerID = 1, .CompanyName = "Contoso, Ltd", .City = "Halifax", .Country = "Canada"},
            New Customer With {.CustomerID = 2, .CompanyName = "Margie's Travel", .City = "Redmond", .Country = "United States"},
            New Customer With {.CustomerID = 3, .CompanyName = "Fabrikam, Inc.", .City = "Vancouver", .Country = "Canada"}
        }
End Function

' Return a list of orders.
Private Function GetOrders() As List(Of Order)
    Return New List(Of Order) From
        {
            New Order With {.CustomerID = 1, .Amount = "200.00"},
            New Order With {.CustomerID = 3, .Amount = "600.00"},
            New Order With {.CustomerID = 1, .Amount = "300.00"},
            New Order With {.CustomerID = 2, .Amount = "100.00"},
            New Order With {.CustomerID = 3, .Amount = "800.00"}
        }
End Function

' Customer Class.
Private Class Customer
    Public Property CustomerID As Integer
    Public Property CompanyName As String
    Public Property City As String
    Public Property Country As String
End Class

' Order Class.
Private Class Order
    Public Property CustomerID As Integer
    Public Property Amount As Decimal
End Class

LINQ プロバイダー

"LINQ プロバイダー" は、Visual Basic LINQ クエリを、クエリ対象のデータ ソースにマップします。 LINQ クエリを記述すると、そのクエリは、プロバイダーによって、データ ソースが実行できるコマンドに変換されます。 プロバイダーは、ソースのデータを、クエリ結果を構成するオブジェクトに変換する操作も行います。 最後に、プロバイダーは、データ ソースに更新が送信されるときに、オブジェクトをデータに変換します。

Visual Basic には、次の LINQ プロバイダーが含まれています。

プロバイダー 説明
LINQ to Objects LINQ to Objects プロバイダーは、インメモリ コレクションとインメモリ配列のクエリを可能にします。 オブジェクトが IEnumerable インターフェイスまたは IEnumerable<T> インターフェイスをサポートしている場合、LINQ to Objects プロバイダーを使用してクエリを実行できます。

LINQ to Objects プロバイダーを有効にするには、すべての Visual Basic プロジェクトに対して既定でインポートされる System.Linq 名前空間をインポートします。

LINQ to Objects プロバイダーの詳細については、「LINQ to Objects」を参照してください。
LINQ to SQL LINQ to SQL プロバイダーは、SQL Server データベース内のデータのクエリと変更を可能にします。 これにより、アプリケーションのオブジェクト モデルを、データベース内のテーブルとオブジェクトに簡単に対応付けることができます。

Visual Basic では、オブジェクト リレーショナル デザイナー (O/R デザイナー) を用意することで、LINQ to SQL の操作を容易にしています。 このデザイナーを使用して、データベース内のオブジェクトに対応付けられるアプリケーション内のオブジェクト モデルを作成します。 O/R デザイナーは、ストアド プロシージャと関数を DataContext オブジェクト (データベースとの通信を管理し、オプティミスティック同時実行制御チェックの状態を保存します) にマップする機能も備えています。

LINQ to SQL プロバイダーの詳細については、「LINQ to SQL」を参照してください。 オブジェクト リレーショナル デザイナーの詳細については、「Visual Studio の LINQ to SQL ツール」を参照してください。
LINQ to XML LINQ to XML プロバイダーは、XML のクエリと変更を可能にします。 インメモリ XML を変更することや、XML をファイルから読み込んだりファイルに保存したりすることができます。

さらに、LINQ to XML プロバイダーでは、XML リテラルと XML 軸プロパティを使用して、XML を Visual Basic コード内に直接記述できます。 詳細については、「XML」を参照してください。
LINQ to DataSet LINQ to DataSet プロバイダーは、ADO.NET データセット内のデータのクエリと更新を可能にします。 データセットを使用するアプリケーションに LINQ を追加することで、データセット内のデータのクエリ、集計、および更新などの機能を単純化すると同時に拡張できます。

詳細については、「LINQ to DataSet」を参照してください。

LINQ クエリの構造

LINQ クエリ ("クエリ式" とも呼ばれます) は、データ ソースを識別するクエリ句と、クエリの反復変数の組み合わせで構成されます。 クエリ式には、並べ替え、フィルター処理、グループ化、および結合を実行する命令や、ソース データに適用する演算も指定できます。 クエリ式の構文は SQL の構文に似ているので、ほとんどの構文は、改めて覚える必要はありません。

クエリ式は、From 句で始まります。 この句は、クエリのソース データと、ソース データの各要素を個別に参照するために使用される変数を識別します。 これらの変数は、"範囲変数" または "反復変数" と呼ばれます。 From 句は、Aggregate クエリ以外のクエリでは必須です。このクエリでは、From 句は省略できます。 From 句または Aggregate 句でクエリのスコープとソースを識別した後、クエリを絞り込むためのクエリ句を自由に組み合わせて記述できます。 クエリ句の詳細については、このトピックの「Visual Basic LINQ クエリ演算子」を参照してください。 たとえば、次のクエリでは、顧客データのソース コレクションを customers 変数として識別し、cust という名前の反復変数を識別します。

Dim customers = GetCustomers()

Dim queryResults = From cust In customers

For Each result In queryResults
    Debug.WriteLine(result.CompanyName & "  " & result.Country)
Next

' Output:
'   Contoso, Ltd  Canada
'   Margie's Travel  United States
'   Fabrikam, Inc.  Canada

この例はそのままでも有効なクエリですが、結果を絞り込むクエリ句を追加すると、はるかに強力なクエリになります。 たとえば、Where 句を追加して、結果を 1 つ以上の値でフィルター処理できます。 クエリ式は、1 行のコードです。追加のクエリ句は、クエリの末尾に単純に追加できます。 クエリを読みやすくするために、行連結文字のアンダースコア (_) を使用して、複数のテキスト行に分割できます。 次のコード例は、Where 句を含むクエリの例を示しています。

Dim queryResults = From cust In customers
                   Where cust.Country = "Canada"

別の強力なクエリ句として、Select 句があります。この句を使用すると、データ ソースから選択したフィールドだけを返すことができます。 LINQ クエリは、厳密に型指定されたオブジェクトの列挙可能なコレクションを返します。 クエリは、匿名型または名前付きの型のコレクションを返すことができます。 Select 句を使用して、データ ソースから単一のフィールドを返すことができます。 これを行った場合、返されるコレクションの型は、その単一のフィールドの型になります。 Select 句を使用して、データ ソースから複数のフィールドを返すこともできます。 これを行った場合、返されるコレクションの型は、新しい匿名型になります。 クエリで返されたフィールドを、指定した名前付きの型のフィールドと一致させることもできます。 次のコード例は、データ ソースから選択されたフィールドのデータが設定されたメンバーのコレクションで、匿名型のコレクションを返すクエリ式を示します。

Dim queryResults = From cust In customers
               Where cust.Country = "Canada"
               Select cust.CompanyName, cust.Country

LINQ クエリを使用して、複数のデータ ソースを結合し、単一の結果を返すこともできます。 これは、1 つまたは複数の From 句を使用するか、Join クエリ句または Group Join クエリ句を使用して実行できます。 次のコード例は、顧客データと注文データを結合し、顧客データと注文データが格納された匿名型のコレクションを返すクエリ式を示します。

Dim customers = GetCustomers()
Dim orders = GetOrders()

Dim queryResults = From cust In customers, ord In orders
           Where cust.CustomerID = ord.CustomerID
           Select cust, ord

For Each result In queryResults
    Debug.WriteLine(result.ord.Amount & "  " & result.ord.CustomerID & "  " & result.cust.CompanyName)
Next

' Output:
'   200.00  1  Contoso, Ltd
'   300.00  1  Contoso, Ltd
'   100.00  2  Margie's Travel
'   600.00  3  Fabrikam, Inc.
'   800.00  3  Fabrikam, Inc.

Group Join 句を使用して、顧客オブジェクトのコレクションを格納する階層的なクエリ結果を作成できます。 各顧客オブジェクトには、その顧客のすべての注文のコレクションを含むプロパティがあります。 次のコード例は、顧客データと注文データを階層的な結果として結合し、匿名型のコレクションを返すクエリ式を示します。 このクエリは、顧客の注文データのコレクションを格納する CustomerOrders プロパティを含む型を返します。 その顧客のすべての注文の合計を格納する OrderTotal プロパティも含まれます (このクエリは、LEFT OUTER JOIN と同等です)。

Dim customers = GetCustomers()
Dim orders = GetOrders()

Dim queryResults = From cust In customers
                   Group Join ord In orders On
                     cust.CustomerID Equals ord.CustomerID
                     Into CustomerOrders = Group,
                          OrderTotal = Sum(ord.Amount)
                   Select cust.CompanyName, cust.CustomerID,
                          CustomerOrders, OrderTotal

For Each result In queryResults
    Debug.WriteLine(result.OrderTotal & "  " & result.CustomerID & "  " & result.CompanyName)
    For Each ordResult In result.CustomerOrders
        Debug.WriteLine("   " & ordResult.Amount)
    Next
Next

' Output:
'   500.00  1  Contoso, Ltd
'      200.00
'      300.00
'   100.00  2  Margie's Travel
'      100.00
'   1400.00  3  Fabrikam, Inc.
'      600.00
'      800.00

上記以外にも、強力なクエリ式を作成するために使用できる、さまざまな LINQ クエリ演算子があります。 このトピックの次のセクションで、クエリ式で使用できるさまざまなクエリ句について説明します。 Visual Basic クエリ句の詳細については、「クエリ」を参照してください。

Visual Basic LINQ クエリ演算子

LINQ クエリをサポートする System.Linq 名前空間とその他の名前空間のクラスには、アプリケーションの要件に基づいてクエリの作成と絞り込みを行うために呼び出すことができるメソッドが含まれています。 Visual Basic には、次の一般的なクエリ句のキーワードが含まれます。 Visual Basic クエリ句の詳細については、「クエリ」を参照してください。

From 句

クエリを開始するには、Fromまたは Aggregate 句のいずれかが必要です。 From 句は、クエリのソース コレクションと反復変数を指定します。 次に例を示します。

' Returns the company name for all customers for which
' the Country is equal to "Canada".
Dim names = From cust In customers
            Where cust.Country = "Canada"
            Select cust.CompanyName

Select 句

任意。 Selectは、クエリの反復変数のセットを宣言します。 次に例を示します。

' Returns the company name and ID value for each
' customer as a collection of a new anonymous type.
Dim customerList = From cust In customers
                   Select cust.CompanyName, cust.CustomerID

Select 句の指定がない場合、クエリの反復変数は、From 句または Aggregate 句で指定された反復変数で構成されます。

Where 句

任意。 Whereは、クエリのフィルター処理条件を指定します。 次に例を示します。

' Returns all product names for which the Category of
' the product is "Beverages".
Dim names = From product In products
            Where product.Category = "Beverages"
            Select product.Name

Order By 句

任意。 Order Byは、クエリ内に列の並べ替え順序を指定します。 次に例を示します。

' Returns a list of books sorted by price in 
' ascending order.
Dim titlesAscendingPrice = From b In books
                           Order By b.price

Join 句

任意。 Joinは、2 つのコレクションを単一のコレクションに結合します。 次に例を示します。

' Returns a combined collection of all of the 
' processes currently running and a descriptive
' name for the process taken from a list of 
' descriptive names.
Dim processes = From proc In Process.GetProcesses
                Join desc In processDescriptions
                  On proc.ProcessName Equals desc.ProcessName
                Select proc.ProcessName, proc.Id, desc.Description

Group By 句

任意。 Group Byは、クエリ結果の要素をグループ化します。 これを使用して、グループごとに集計関数を適用できます。 次に例を示します。

' Returns a list of orders grouped by the order date
' and sorted in ascending order by the order date.
Dim orderList = From order In orders
                Order By order.OrderDate
                Group By OrderDate = order.OrderDate
                Into OrdersByDate = Group

Group Join 句

任意。 Group Joinは、2 つのコレクションを単一の階層コレクションに結合します。 次に例を示します。

' Returns a combined collection of customers and
' customer orders.
Dim customerList = From cust In customers
                   Group Join ord In orders On
                     cust.CustomerID Equals ord.CustomerID
                   Into CustomerOrders = Group,
                        TotalOfOrders = Sum(ord.Amount)
                   Select cust.CompanyName, cust.CustomerID,
                          CustomerOrders, TotalOfOrders

Aggregate 句

クエリを開始するには、Aggregateまたは From 句のいずれかが必要です。 Aggregate 句は、1 つ以上の集計関数をコレクションに適用します。 たとえば、次の例で行っているように、Aggregate 句を使用して、クエリで返されたすべての要素の合計を計算できます。

' Returns the sum of all order amounts.
Dim orderTotal = Aggregate order In orders
                 Into Sum(order.Amount)

Aggregate 句を使用してクエリを変更することもできます。 たとえば、Aggregate 句を使用して、関連するクエリ コレクションに対して計算を実行できます。 次に例を示します。

' Returns the customer company name and largest 
' order amount for each customer.
Dim customerMax = From cust In customers
                  Aggregate order In cust.Orders
                  Into MaxOrder = Max(order.Amount)
                  Select cust.CompanyName, MaxOrder

Let 句

任意。 Letは、値を計算し、それをクエリ内の新しい変数に代入します。 次に例を示します。

' Returns a list of products with a calculation of
' a ten percent discount.
Dim discountedProducts = From prod In products
                         Let Discount = prod.UnitPrice * 0.1
                         Where Discount >= 50
                         Select prod.Name, prod.UnitPrice, Discount

Distinct 句

任意。 Distinct 句は、現在の反復変数の値を制限して、クエリ結果内で重複する値を除去します。 次に例を示します。

' Returns a list of cities with no duplicate entries.
Dim cities = From item In customers
             Select item.City
             Distinct

Skip 句

任意。 Skipは、コレクション内の指定された数の要素をバイパスし、残りの要素を返します。 次に例を示します。

' Returns a list of customers. The first 10 customers
' are ignored and the remaining customers are
' returned.
Dim customerList = From cust In customers
                   Skip 10

Skip While 句

任意。 Skip Whileは、指定された条件が true である限り、コレクションの要素をバイパスし、残りの要素を返します。 次に例を示します。

' Returns a list of customers. The query ignores all
' customers until the first customer for whom
' IsSubscriber returns false. That customer and all
' remaining customers are returned.
Dim customerList = From cust In customers
                   Skip While IsSubscriber(cust)

Take 句

任意。 Takeは、コレクションの先頭から、指定された数の連続する要素を返します。 次に例を示します。

' Returns the first 10 customers.
Dim customerList = From cust In customers
                   Take 10

Take While 句

任意。 Take Whileは、指定された条件が true である限り、コレクションの要素を含むようにし、残りの要素をバイパスします。 次に例を示します。

' Returns a list of customers. The query returns
' customers until the first customer for whom 
' HasOrders returns false. That customer and all 
' remaining customers are ignored.
Dim customersWithOrders = From cust In customers
                          Order By cust.Orders.Count Descending
                          Take While HasOrders(cust)

追加の LINQ クエリ機能の使用

LINQ によって提供される列挙可能でクエリ可能な型のメンバーを呼び出すことで、追加の LINQ クエリ機能を使用できます。 これらの追加機能は、クエリ式の結果に対して特定のクエリ演算子を呼び出すことで使用できます。 たとえば、次の例では、Enumerable.Union メソッドを使用して、2 つのクエリの結果を、1 つのクエリ結果に結合します。 また、Enumerable.ToList メソッドを使用して、クエリ結果をジェネリック リストとして返します。

Public Function GetAllCustomers() As List(Of Customer)
    Dim customers1 = From cust In domesticCustomers
    Dim customers2 = From cust In internationalCustomers

    Dim customerList = customers1.Union(customers2)

    Return customerList.ToList()
End Function

その他の LINQ 機能の詳細については、「標準クエリ演算子の概要」を参照してください。

LINQ to SQL を使用したデータベースへの接続

Visual Basic では、アクセスする SQL Server データベース オブジェクト (テーブル、ビュー、ストアド プロシージャなど) を、LINQ to SQL ファイルを使用して識別します。 LINQ to SQL ファイルには、.dbml という拡張子が付きます。

SQL Server データベースへの有効な接続が存在する場合は、LINQ to SQL クラス項目テンプレートをプロジェクトに追加できます。 これを行うと、オブジェクト リレーショナル デザイナー (O/R デザイナー) が表示されます。 O/R デザイナーを使用して、コード内でアクセスする項目を、サーバー エクスプローラー/データベース エクスプローラーからデザイナー画面にドラッグできます。 LINQ to SQL ファイルは、DataContext オブジェクトをプロジェクトに追加します。 このオブジェクトには、アクセスするテーブルとビューのプロパティおよびコレクションと、呼び出すストアド プロシージャのメソッドが格納されます。 変更を LINQ to SQL (.dbml) ファイルに保存した後、O/R デザイナーで定義された DataContext オブジェクトを参照することで、コード内でこれらのオブジェクトにアクセスできます。 プロジェクトの DataContext オブジェクトには、LINQ to SQL ファイルの名前に基づいて名前が付けられます。 たとえば、Northwind.dbml という名前の LINQ to SQL ファイルの場合は、DataContext という名前の NorthwindDataContext オブジェクトが作成されます。

詳細な手順を示した例については、「方法: データベースに対してクエリを実行する」と「方法: ストアド プロシージャの呼び出し」を参照してください。

LINQ をサポートする Visual Basic の機能

Visual Basic には、LINQ の使用を単純化し、LINQ クエリを実行するために記述する必要があるコードの量を減らすことができる、注目に値する機能が他にもあります。 次に例を示します。

  • 匿名型。クエリ結果に基づいて、新しい型を作成できます。

  • 暗黙的に型指定される変数。型の指定を遅らせ、クエリ結果に基づいてコンパイラで型を推論できます。

  • 拡張メソッド。型自体を変更することなく、独自のメソッドを使用して既存の型を拡張できます。

詳細については、「LINQ をサポートする Visual Basic の機能」を参照してください。

クエリの遅延実行と即時実行

クエリの実行とクエリの作成は分離しています。 クエリを作成した後、その実行は、別のメカニズムによってトリガーされます。 クエリは、定義後すぐに実行 ("即時実行)" することも、定義を保存しておき、後でクエリを実行 ("遅延実行") することもできます。

既定では、クエリを作成しても、クエリ自体が直ちに実行されることはありません。 代わりに、クエリ結果を参照するために使用される変数にクエリ定義が格納されます。 そのクエリ結果変数が、後でコード内の For…Next ループなどでアクセスされると、クエリが実行されます。 この処理を "遅延実行" と呼びます。

クエリは、それを定義したときに実行することもできます。これを "即時実行" と呼びます。 即時実行は、クエリ結果の個々の要素にアクセスする必要があるメソッドを適用することで開始できます。 CountSumAverageMinMax などの集計関数を含めることで、この結果を得ることができます。 集計関数の詳細については、「Aggregate 句」を参照してください。

ToList メソッドまたは ToArray メソッドを使用することでも、即時実行を開始できます。 これは、クエリを直ちに実行し、結果をキャッシュする場合に役に立ちます。 これらのメソッドの詳細については、「データ型の変換」を参照してください。

クエリの実行の詳細については、「初めての LINQ クエリの作成」を参照してください。

Visual Basic における XML

Visual Basic における XML の機能には、XML リテラルと XML 軸プロパティがあります。これらを使用して、コード内で XML を簡単に作成、アクセス、照会、および変更できます。 XML リテラルを使用すると、XML をコード内に直接記述できます。 Visual Basic コンパイラは、XML を、最初のクラスのデータ オブジェクトとして処理します。

次のコード例は、XML 要素を作成し、そのサブ要素と属性にアクセスし、LINQ を使用してその要素の内容を照会する方法を示しています。

' Place Imports statements at the top of your program.
Imports <xmlns:ns="http://SomeNamespace">

Module Sample1

    Sub SampleTransform()

        ' Create test by using a global XML namespace prefix.

        Dim contact =
            <ns:contact>
                <ns:name>Patrick Hines</ns:name>
                <ns:phone ns:type="home">206-555-0144</ns:phone>
                <ns:phone ns:type="work">425-555-0145</ns:phone>
            </ns:contact>

        Dim phoneTypes =
          <phoneTypes>
              <%= From phone In contact.<ns:phone>
                  Select <type><%= phone.@ns:type %></type>
              %>
          </phoneTypes>

        Console.WriteLine(phoneTypes)
    End Sub

End Module

詳細については、「XML」を参照してください。

トピック 説明
XML Visual Basic における XML の機能について説明します。これらの機能を使用すると、クエリを実行したり、XML を最初のクラスのデータ オブジェクトとして Visual Basic コード内に含めたりすることができます。
クエリ Visual Basic で使用できるクエリ句のリファレンス情報を示します。
統合言語クエリ (LINQ) LINQ の概要、プログラミング ガイド、およびサンプルを示します。
LINQ to SQL LINQ to SQL の概要、プログラミング ガイド、およびサンプルを示します。
LINQ to Objects LINQ to Objects の概要、プログラミング ガイド、およびサンプルを示します。
LINQ to ADO.NET (ポータル ページ) LINQ to ADO.NET の概要、プログラミング ガイド、およびサンプルへのリンクを示します。
LINQ to XML LINQ to XML の概要、プログラミング ガイド、およびサンプルを示します。

方法とチュートリアルのトピック

方法: データベースに対してクエリを実行する

方法: ストアド プロシージャの呼び出し

方法: データベースのデータの変更

方法: 結合を使用したデータの結合

方法: クエリ結果を並べ替える

方法: クエリ結果をフィルター処理する

方法: データの数、合計、または平均の算出

方法: クエリ結果内の最小値と最大値の検索

方法: 更新、挿入、および削除を実行するストアド プロシージャを割り当てる (O/R デザイナー)

第 17 章: LINQ」 (『Programming Visual Basic 2008』)

関連項目