チュートリアル : Visual Basic でのクエリの作成
更新 : 2007 年 11 月
このチュートリアルでは、Visual Basic 2008 言語の新機能について説明し、これらの機能を使用して 統合言語クエリ (LINQ: Language-Integrated Query) のクエリ式を記述する方法を紹介します。ここでは、Student オブジェクトのリストの作成方法、クエリの実行方法、およびクエリの変更方法を示します。クエリには、オブジェクト初期化子、ローカル型の推論、匿名型など、Visual Basic 2008 のいくつかの新機能が組み込まれています。
このチュートリアルを完了したら、関心のある特定の LINQ プロバイダのサンプルやドキュメントに進むことができます。LINQ プロバイダには、LINQ to SQL、LINQ to DataSet、LINQ to XML などがあります。
ビデオ デモについては、「Video How to: Writing Queries in Visual Basic」を参照してください。
プロジェクトの作成
.NET Framework Version 3.5 以降を対象とするプロジェクトを作成するには
Visual Studio 2008 を起動します。
[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
[コンソール アプリケーション] をクリックし、[OK] をクリックします。
プロジェクトが作成されます。プロジェクトには、System.Core.dll への参照と、System.Linq 名前空間に対する Imports ステートメントが既定で含まれます。どちらも LINQ クエリを実行するために必要です。
インメモリ データ ソースの追加
このチュートリアルのクエリのデータ ソースは、Student オブジェクトのリストです。各 Student オブジェクトには、名、姓、学年、および学生全体における成績順位が含まれます。
データ ソースを追加するには
Student クラスを定義し、そのクラスのインスタンスのリストを作成します。
重要 : このチュートリアルの例で使用する Student クラスの定義とリストの作成に必要なコードは、「方法 : 項目のリストを作成する」に記載されています。そこからコードをコピーし、プロジェクトに貼り付けることができます。プロジェクトの作成時に表示されたコードを、新しいコードで置き換えます。
学生のリストに新しい学生を追加するには
- getStudents メソッドのパターンに従って、Student クラスの別のインスタンスをリストに追加します。学生を追加すると、オブジェクト初期化子が導入されます。これは Visual Basic 2008 の新機能です。詳細については、「オブジェクト初期化子 : 名前付きの型と匿名型」を参照してください。
クエリの作成
このセクションで追加したクエリが実行されると、成績順位が上位 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 クエリの作成 (Visual Basic)」を参照してください。
クエリを実行するには
プロジェクト内のクエリの下に、次の For Each ループを追加します。
For Each studentRecord In studentQuery Console.WriteLine(studentRecord.Last & ", " & studentRecord.First) Next
マウス ポインタをループ制御変数 studentRecord の上に置き、データ型を確認します。studentQuery は Student インスタンスのコレクションを返すので、studentRecord の型は Student であると推論されます。
Ctrl キーを押しながら F5 キーを押して、アプリケーションをビルドおよび実行します。コンソール ウィンドウで結果を確認します。
クエリの変更
クエリ結果が指定した順序で並んでいると、結果のスキャンが簡単になります。使用可能な任意のフィールドに基づいて、返されるシーケンスを並べ替えることができます。
結果を順序に従って並べるには
次の Order By 句を、クエリの Where ステートメントと Select ステートメントの間に追加します。この 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 句で匿名型を作成するには
クエリで匿名型がどのように使用されるかを確認するには、このセクションのコードを追加します。匿名型は、Visual Basic 2008 の新機能です。これは、クエリで完全なレコード (前の例の currentStudent レコード) や単一のフィールド (前の例の First) を返すのではなく、データ ソースからいくつかのフィールドを返す場合に使用します。結果に含めるフィールドを保持する新しい名前付きの型を定義する代わりに、必要なフィールドを Select 句で指定すると、コンパイラによって、それらのフィールドをプロパティとして持つ匿名型が作成されます。詳細については、「匿名型」を参照してください。
次の例では、成績順位が 1 位から 10 位までの最上級生の名前と順位を成績順に返すクエリを作成します。この例では、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 プロバイダのドキュメントやサンプルに進むことができます。