チュートリアル: Visual Basic でのクエリの作成
このチュートリアルでは、Visual Basic 言語の機能を使用して統合言語クエリ (LINQ) のクエリ式を記述する方法を示します。 このチュートリアルでは、Student オブジェクトのリストに対するクエリを作成する方法とそのクエリを実行する方法、さらにクエリに変更を加える方法について説明します。 クエリには、オブジェクト初期化子、ローカル型推論、匿名型などさまざまな機能が組み込まれています。
このチュートリアルを完了すれば、いつでも、興味がある特定の LINQ プロバイダーのサンプルやドキュメントに進むことができます。 LINQ プロバイダーには、LINQ to SQL、LINQ to DataSet、LINQ to XML が含まれます。
プロジェクトの作成
コンソール アプリケーション プロジェクトを作成するには
Visual Studio を起動します。
[ファイル] メニューの [新規作成] をポイントし、 [プロジェクト] をクリックします。
[インストールされたテンプレート] の一覧で、 [Visual Basic] をクリックします。
プロジェクトの種類の一覧の [コンソール アプリケーション] をクリックします。 [名前] ボックスにプロジェクトの名前を入力して、 [OK] をクリックします。
プロジェクトが作成されます。 System.Core.dll への参照は、既定で追加されます。 また、プロジェクト デザイナー (Visual Basic) の [参照] ページにある [インポートされた名前空間] の一覧には System.Linq 名前空間が含まれます。
プロジェクト デザイナー (Visual Basic) の [コンパイル] ページで、 [Option infer] が [On] に設定されていることを確認します。
インメモリ データ ソースを追加する
このチュートリアルで使用するクエリのデータ ソースは、Student
オブジェクトのリストです。 それぞれの Student
オブジェクトには、名、姓、学年、全学生における成績のランクが格納されます。
データ ソースを追加するには
Student
クラスを定義し、クラスのインスタンスのリストを作成します。重要
Student
クラスを定義し、このチュートリアルの各例で使用するリストを作成するために必要なコードは、「方法: 項目のリストを作成する」に掲載されています。 そこからコピーして、自分のプロジェクトに貼り付けてください。 プロジェクトの作成時にあったコードを新しいコードで置き換えます。
学生リストに新しい学生を追加するには
getStudents
メソッドのパターンに従って、Student
クラスのインスタンスを新たにリストに追加します。 学生を追加すると、オブジェクト初期化子が挿入されます。 詳細については、「オブジェクト初期化子: 名前付きの型と匿名型」を参照してください。
クエリを作成する
このセクションで追加したクエリを実行すると、成績のランクがトップ 10 に入る学生のリストが生成されます。 このクエリでは都度、完全な Student
オブジェクトが選択されるため、クエリの結果の型は IEnumerable(Of Student)
です。 ただし通常、クエリの定義にクエリの型は指定されません。 コンパイラがローカル型推論を使用して型を特定します。 詳細については、「ローカル型の推論」を参照してください。 クエリの範囲変数 currentStudent
は、ソース students
に含まれる各 Student
インスタンスへの参照として機能します。students
内の各オブジェクトのプロパティには、それを通じてアクセスすることができます。
簡単なクエリを作成するには
プロジェクトの
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
コード内の
studentQuery
にマウス ポインターを合わせて、コンパイラによって割り当てられた型がIEnumerable(Of Student)
であることを確認します。
クエリを実行する
変数 studentQuery
には、クエリの実行結果ではなくクエリの定義が格納されます。 クエリを実行するための通常のメカニズムは For Each
ループです。 返されたシーケンス内の各要素には、ループの反復変数を介してアクセスします。 クエリの実行の詳細については、「初めての LINQ クエリの作成」を参照してください。
クエリを実行するには
対象のプロジェクトで、クエリの下に次の
For Each
ループを追加します。For Each studentRecord In studentQuery Console.WriteLine(studentRecord.Last & ", " & studentRecord.First) Next
ループの制御変数
studentRecord
にマウス ポインターを合わせて、そのデータ型を確認します。studentQuery
から返されるのはStudent
インスタンスのコレクションであるため、studentRecord
の型もStudent
であると推定されます。Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。
クエリの変更
クエリの結果は、特定の順序で並んでいた方が見やすくなります。 返されたシーケンスは、使用できるあらゆるフィールドを基準にして並べ替えることができます。
結果を並べ替えるには
クエリの
Where
ステートメントとSelect
ステートメントの間に、次のOrder By
句を追加します。Order By
句は、各学生の姓を基準にして、A から Z のアルファベット順に結果を並べ替えます。Order By currentStudent.Last Ascending
まず姓で並べ替えたうえで、名で並べ替えるために、その両方のフィールドをクエリに追加します。
Order By currentStudent.Last Ascending, currentStudent.First Ascending
Descending
を指定して、Z から A の順に並べ替えることもできます。Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。
ローカルの識別子を挿入するには
ローカルの識別子をクエリ式に挿入するには、このセクションのコードを追加します。 ローカルの識別子には中間結果が保持されます。 次の例の
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
Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。
Select 句で 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
コード内の
studentQuery3
にマウス ポインターを合わせて、割り当てられた型がIEnumerable(Of String)
であることを確認します。Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 コンソール ウィンドウで結果を確認してください。
Select 句で匿名型を作成するには
クエリにおける匿名型の使用法を確認するために、このセクションのコードを追加します。 これらをクエリで使用するのは、レコード全体 (前の例では
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
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 プロバイダーについて、ドキュメントやサンプルを読んでみましょう。
関連項目
.NET