演练:用 Visual Basic 编写查询
更新:2011 年 5 月
本演练演示了如何使用 Visual Basic 语言功能来编写 语言集成查询 (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 中编写查询)。
创建项目
创建控制台应用程序项目
启动 Visual Studio。
在**“文件”菜单上指向“新建”,再单击“项目”**。
在**“已安装的模板”列表中,单击“Visual Basic”**。
在应用程序类型列表中,单击**“控制台应用程序”。 在“名称”框中键入项目的名称,然后单击“确定”**。
随即创建一个项目。 默认情况下,此项目包含对 System.Core.dll 的引用。 此外,项目设计器 ->“引用”页 (Visual Basic) 上的**“导入的命名空间”**列表中还包括 System.Linq 命名空间。
添加内存中数据源
本演练中查询的数据源是 Student 对象列表。 每个 Student 对象都包含名、姓、年级和在全体学生中的学习名次。
添加数据源
定义 Student 类,然后创建该类的实例列表。
重要事项 如何:创建项列表中提供了定义 Student 类和创建演练示例所使用的列表所需的代码。 您可以复制这些代码并将其粘贴到您的项目中。 新代码用于替换在您创建项目时显示的代码。
在学生列表中添加新学生
- 按照 getStudents 方法中的模式将 Student 类的另一个实例添加到列表中。 添加学生涉及到对象初始值设定项。 有关更多信息,请参见对象初始值设定项:命名类型和匿名类型 (Visual Basic)。
创建查询
执行本节添加的查询时,将生成学习名次位于前十位的学生列表。 由于查询每次都选择整个 Student 对象,因此查询结果的类型是 IEnumerable(Of Student)。 但是,查询的类型通常不在查询定义中指定, 而是由编译器使用局部类型推理来确定。 有关更多信息,请参见局部类型推理 (Visual Basic)。 查询的范围变量 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 上,以查看其数据类型。 studentRecord 类型被推断为 Student,因为 studentQuery 返回 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 子句中投影一个字段
添加本节中的查询和 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
将鼠标指针停留在代码中的 studentQuery3 上,以验证分配的类型是否为 IEnumerable(Of String)。
按 CTRL+F5 生成并运行该应用程序。 注意控制台窗口中的结果。
在 Select 子句中创建匿名类型
添加本节中的代码以了解在查询中如何使用匿名类型。 当您希望从数据源返回多个字段而不是返回完整记录(前面示例中的 currentStudent 记录)或单个字段(前一节中的 First)时,可以在查询中使用匿名类型。 可以在 Select 子句中指定要包括在结果中的字段,然后编译器将创建一个以这些字段作为属性的匿名类型,而不需要定义包含这些字段的新命名类型。有关更多信息,请参见匿名类型 (Visual Basic)。
下面的示例创建一个查询,返回学习名次位于 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 提供程序的文档和示例:
请参见
任务
概念
对象初始值设定项:命名类型和匿名类型 (Visual Basic)
其他资源
修订记录
日期 |
修订记录 |
原因 |
---|---|---|
2011 年 5 月 |
修订了“创建项目”一节。 |
内容 Bug 修复 |