チュートリアル: Visual Basic でのクエリの作成

このチュートリアルでは、Visual Basic 言語の機能を使用して統合言語クエリ (LINQ) のクエリ式を記述する方法を示します。 このチュートリアルでは、Student オブジェクトのリストに対するクエリを作成する方法とそのクエリを実行する方法、さらにクエリに変更を加える方法について説明します。 クエリには、オブジェクト初期化子、ローカル型推論、匿名型などさまざまな機能が組み込まれています。

このチュートリアルを完了すれば、いつでも、興味がある特定の LINQ プロバイダーのサンプルやドキュメントに進むことができます。 LINQ プロバイダーには、LINQ to SQL、LINQ to DataSet、LINQ to XML が含まれます。

プロジェクトの作成

コンソール アプリケーション プロジェクトを作成するには

  1. Visual Studio を起動します。

  2. [ファイル] メニューの [新規作成] をポイントし、 [プロジェクト] をクリックします。

  3. [インストールされたテンプレート] の一覧で、 [Visual Basic] をクリックします。

  4. プロジェクトの種類の一覧の [コンソール アプリケーション] をクリックします。 [名前] ボックスにプロジェクトの名前を入力して、 [OK] をクリックします。

    プロジェクトが作成されます。 System.Core.dll への参照は、既定で追加されます。 また、プロジェクト デザイナー (Visual Basic) の [参照] ページにある [インポートされた名前空間] の一覧には System.Linq 名前空間が含まれます。

  5. プロジェクト デザイナー (Visual Basic) の [コンパイル] ページで、 [Option infer][On] に設定されていることを確認します。

インメモリ データ ソースを追加する

このチュートリアルで使用するクエリのデータ ソースは、Student オブジェクトのリストです。 それぞれの Student オブジェクトには、名、姓、学年、全学生における成績のランクが格納されます。

データ ソースを追加するには

  • Student クラスを定義し、クラスのインスタンスのリストを作成します。

    重要

    Student クラスを定義し、このチュートリアルの各例で使用するリストを作成するために必要なコードは、「方法: 項目のリストを作成する」に掲載されています。 そこからコピーして、自分のプロジェクトに貼り付けてください。 プロジェクトの作成時にあったコードを新しいコードで置き換えます。

学生リストに新しい学生を追加するには

  • getStudents メソッドのパターンに従って、Student クラスのインスタンスを新たにリストに追加します。 学生を追加すると、オブジェクト初期化子が挿入されます。 詳細については、「オブジェクト初期化子: 名前付きの型と匿名型」を参照してください。

クエリを作成する

このセクションで追加したクエリを実行すると、成績のランクがトップ 10 に入る学生のリストが生成されます。 このクエリでは都度、完全な Student オブジェクトが選択されるため、クエリの結果の型は IEnumerable(Of Student) です。 ただし通常、クエリの定義にクエリの型は指定されません。 コンパイラがローカル型推論を使用して型を特定します。 詳細については、「ローカル型の推論」を参照してください。 クエリの範囲変数 currentStudent は、ソース students に含まれる各 Student インスタンスへの参照として機能します。students 内の各オブジェクトのプロパティには、それを通じてアクセスすることができます。

簡単なクエリを作成するには

  1. プロジェクトの Main メソッドから、次のように記述されている箇所を見つけます。

    ' ****Paste query and query execution code from the walkthrough,
    ' ****or any code of your own, here in Main.
    

    次のコードをコピーして、そこに貼り付けます。

    Dim studentQuery = From currentStudent In students
                       Where currentStudent.Rank <= 10
                       Select currentStudent
    
  2. コード内の studentQuery にマウス ポインターを合わせて、コンパイラによって割り当てられた型が IEnumerable(Of Student) であることを確認します。

クエリを実行する

変数 studentQuery には、クエリの実行結果ではなくクエリの定義が格納されます。 クエリを実行するための通常のメカニズムは For Each ループです。 返されたシーケンス内の各要素には、ループの反復変数を介してアクセスします。 クエリの実行の詳細については、「初めての LINQ クエリの作成」を参照してください。

クエリを実行するには

  1. 対象のプロジェクトで、クエリの下に次の For Each ループを追加します。

    For Each studentRecord In studentQuery
        Console.WriteLine(studentRecord.Last & ", " & studentRecord.First)
    Next
    
  2. ループの制御変数 studentRecord にマウス ポインターを合わせて、そのデータ型を確認します。 studentQuery から返されるのは Student インスタンスのコレクションであるため、studentRecord の型も Student であると推定されます。

  3. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。

クエリの変更

クエリの結果は、特定の順序で並んでいた方が見やすくなります。 返されたシーケンスは、使用できるあらゆるフィールドを基準にして並べ替えることができます。

結果を並べ替えるには

  1. クエリの Where ステートメントと Select ステートメントの間に、次の Order By 句を追加します。 Order By 句は、各学生の姓を基準にして、A から Z のアルファベット順に結果を並べ替えます。

    Order By currentStudent.Last Ascending
    
  2. まず姓で並べ替えたうえで、名で並べ替えるために、その両方のフィールドをクエリに追加します。

    Order By currentStudent.Last Ascending, currentStudent.First Ascending
    

    Descending を指定して、Z から A の順に並べ替えることもできます。

  3. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。

ローカルの識別子を挿入するには

  1. ローカルの識別子をクエリ式に挿入するには、このセクションのコードを追加します。 ローカルの識別子には中間結果が保持されます。 次の例の name は、学生の名と姓を連結した値を保持する識別子です。 ローカルの識別子は利便性を目的に使用できるほか、式の結果を格納しておくことで、計算を何度も行う必要がなくなるのでパフォーマンスの向上にもつながります。

    Dim studentQuery2 =
            From currentStudent In students
            Let name = currentStudent.Last & ", " & currentStudent.First
            Where currentStudent.Year = "Senior" And currentStudent.Rank <= 10
            Order By name Ascending
            Select currentStudent
    
    ' If you see too many results, comment out the previous
    ' For Each loop.
    For Each studentRecord In studentQuery2
        Console.WriteLine(studentRecord.Last & ", " & studentRecord.First)
    Next
    
  2. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。

Select 句で 1 つのフィールドを投影するには

  1. ソース内の要素とは異なる要素のシーケンスを生成するクエリを作成するには、このセクションのクエリと For Each ループを追加します。 次の例のソースは Student オブジェクトのコレクションですが、返されるのは各オブジェクトの 1 つのメンバー (姓が Garcia である学生の名) だけです。 currentStudent.First は文字列であるため、studentQuery3 から返されるシーケンスのデータ型は IEnumerable(Of String)、つまり一連の文字列です。 これまでの例と同様、studentQuery3 に対するデータ型の割り当ては、コンパイラに委ねられ、ローカル型推論を使用して特定されます。

    Dim studentQuery3 = From currentStudent In students
                        Where currentStudent.Last = "Garcia"
                        Select currentStudent.First
    
    ' If you see too many results, comment out the previous
    ' For Each loops.
    For Each studentRecord In studentQuery3
        Console.WriteLine(studentRecord)
    Next
    
  2. コード内の studentQuery3 にマウス ポインターを合わせて、割り当てられた型が IEnumerable(Of String) であることを確認します。

  3. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。

Select 句で匿名型を作成するには

  1. クエリにおける匿名型の使用法を確認するために、このセクションのコードを追加します。 これらをクエリで使用するのは、レコード全体 (前の例では currentStudent レコード) や単一のフィールド (前セクションの First) ではなく複数のフィールドがデータ ソースから返されるようにしたい場合です。 結果に含めたいフィールドを格納する名前付きの型を新たに定義するのではなく、Select 句でフィールドを指定すると、それらのフィールドをプロパティとして持つ匿名型がコンパイラによって作成されます。 詳細については、「匿名型」を参照してください。

    次の例では、成績のランクが 1 から 10 である最上級生 (Senior) の名前とランクを、成績のランク順に返すクエリを作成しています。 この例では、studentQuery4 の型を推定する必要があります。Select 句で返されるのは匿名型のインスタンスであり、使用できる名前が匿名型にはないためです。

    Dim studentQuery4 =
            From currentStudent In students
            Where currentStudent.Year = "Senior" And currentStudent.Rank <= 10
            Order By currentStudent.Rank Ascending
            Select currentStudent.First, currentStudent.Last, currentStudent.Rank
    
    ' If you see too many results, comment out the previous
    ' For Each loops.
    For Each studentRecord In studentQuery4
        Console.WriteLine(studentRecord.Last & ", " & studentRecord.First &
                          ":  " & studentRecord.Rank)
    Next
    
  2. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。

その他の例

これで基本的な事柄を理解できたので、別の一連の例で、LINQ クエリの柔軟性と機能を見てみましょう。 それぞれの例には、その処理の内容について最初に簡潔な説明が記述されています。 それぞれのクエリの結果変数にマウス ポインターを合わせると、推定された型が表示されます。 結果の生成には、For Each ループを使用します。

' Find all students who are seniors.
Dim q1 = From currentStudent In students
         Where currentStudent.Year = "Senior"
         Select currentStudent

' Write a For Each loop to execute the query.
For Each q In q1
    Console.WriteLine(q.First & " " & q.Last)
Next

' Find all students with a first name beginning with "C".
Dim q2 = From currentStudent In students
         Where currentStudent.First.StartsWith("C")
         Select currentStudent

' Find all top ranked seniors (rank < 40).
Dim q3 = From currentStudent In students
         Where currentStudent.Rank < 40 And currentStudent.Year = "Senior"
         Select currentStudent

' Find all seniors with a lower rank than a student who 
' is not a senior.
Dim q4 = From student1 In students, student2 In students
         Where student1.Year = "Senior" And student2.Year <> "Senior" And
               student1.Rank > student2.Rank
         Select student1
         Distinct

' Retrieve the full names of all students, sorted by last name.
Dim q5 = From currentStudent In students
         Order By currentStudent.Last
         Select Name = currentStudent.First & " " & currentStudent.Last

' Determine how many students are ranked in the top 20.
Dim q6 = Aggregate currentStudent In students
         Where currentStudent.Rank <= 20
         Into Count()

' Count the number of different last names in the group of students.
Dim q7 = Aggregate currentStudent In students
         Select currentStudent.Last
         Distinct
         Into Count()

' Create a list box to show the last names of students.
Dim lb As New System.Windows.Forms.ListBox
Dim q8 = From currentStudent In students
         Order By currentStudent.Last
         Select currentStudent.Last Distinct

For Each nextName As String In q8
    lb.Items.Add(nextName)
Next

' Find every process that has a lowercase "h", "l", or "d" in its name.
Dim letters() As String = {"h", "l", "d"}
Dim q9 = From proc In System.Diagnostics.Process.GetProcesses,
         letter In letters
         Where proc.ProcessName.Contains(letter)
         Select proc

For Each proc In q9
    Console.WriteLine(proc.ProcessName & ", " & proc.WorkingSet64)
Next

追加情報

クエリ操作の基本的な概念が理解できたら、興味がある種類の LINQ プロバイダーについて、ドキュメントやサンプルを読んでみましょう。

関連項目