演练:在 Visual Basic 中编写查询

更新:2007 年 11 月

本演练将引导您学习新的 Visual Basic 2008 语言功能,并演示如何使用这些功能来编写语言集成查询 (LINQ) 查询表达式。本演练演示如何对一个 Student 对象列表创建查询、如何运行以及如何修改这些查询。这些查询加入了 Visual Basic 2008 的多项新功能,包括对象初始值设定项、局部类型推理和匿名类型。

完成本演练后,就可以转到所关注的特定 LINQ 提供程序的示例和文档。LINQ 提供程序包括 LINQ to SQL、LINQ to DataSet 和 LINQ to XML。

链接到视频 有关视频演示,请参见 Video How to: Writing Queries in Visual Basic(视频帮助:用 Visual Basic 编写查询)。

创建项目

创建面向 .NET Framework 3.5 或更高版本的项目

  1. 启动 Visual Studio 2008。

  2. 在“文件”菜单上单击“新建项目”。

  3. 单击“控制台应用程序”,再单击“确定”。

    随即创建一个项目。默认情况下,该项目包含对 System.Core.dll 的引用和适用于 System.Linq 命名空间的 Imports 语句,这两者都是运行 LINQ 查询所必需的。

添加内存中数据源

本演练中查询的数据源是 Student 对象列表。每个 Student 对象都包含名、姓、年级和在全体学生中的学习名次。

添加数据源

  • 定义 Student 类,然后创建该类的实例列表。

    重要说明:

    如何:创建项列表中提供了定义 Student 类和创建演练示例所使用的列表所需的代码。您可以复制这些代码并将其粘贴到您的项目中。新代码用于替换在您创建项目时显示的代码。

在学生列表中添加新学生

创建查询

执行本节添加的查询时,将生成学习名次位于前十位的学生列表。由于查询每次都选择整个 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 查询 (Visual Basic)

运行查询

  1. 将下面的 For Each 循环添加到项目中的查询下面。

    For Each studentRecord In studentQuery
        Console.WriteLine(studentRecord.Last & ", " & studentRecord.First)
    Next
    
  2. 将鼠标指针停留在循环控制变量 studentRecord 上,以查看其数据类型。studentRecord 类型被推断为 Student,因为 studentQuery 返回 Student 实例的集合。

  3. 按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。

修改查询

如果结果按指定顺序排列,则浏览查询结果会更容易。您可以根据任何可用字段对返回的序列进行排序。

对结果进行排序

  1. 将下面的 Order By 子句添加到查询的 Where 语句和 Select 语句之间。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. 添加本节中的查询和 For Each 循环以创建一个查询,该查询将生成一个其元素与源中元素不同的序列。在下面的示例中,源是 Student 对象的集合,但是只返回每个对象的一个成员:姓氏为 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. 添加本节中的代码以了解在查询中如何使用匿名类型。匿名类型是 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
    
  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 提供程序的文档和示例:

LINQ to Objects

LINQ to SQL

LINQ to XML

LINQ to DataSet

请参见

任务

示例查询 (Visual Basic)

概念

辅助 LINQ 资源

局部类型推理

对象初始值设定项:命名类型和匿名类型

匿名类型

Visual Basic 中的 LINQ 简介

其他资源

语言集成查询 (LINQ)

Visual Basic 中的 LINQ 入门

Visual Basic 中的 LINQ

查询 (Visual Basic)