Language-Integrated 查询(LINQ)将查询功能添加到 Visual Basic,并在处理所有类型的数据时提供简单而强大的功能。 LINQ 不会将查询发送到要处理的数据库,或者为要搜索的每种类型的数据使用不同的查询语法,而是将查询作为 Visual Basic 语言的一部分引入。 无论数据类型如何,它都使用统一的语法。
LINQ 使你能够查询 SQL Server 数据库、XML、内存中数组和集合、ADO.NET 数据集或支持 LINQ 的任何其他远程或本地数据源中的数据。 可以使用常见的 Visual Basic 语言元素执行此作。 由于查询是以 Visual Basic 语言编写的,因此查询结果将作为强类型对象返回。 这些对象支持 IntelliSense,这使你可以在编译时(而不是运行时)更快地编写代码并捕获查询中的错误。 LINQ 查询可用作其他查询的源,以优化结果。 它们还可以绑定到控件,以便用户可以轻松查看和修改查询结果。
例如,下面的代码示例演示了一个 LINQ 查询,该查询从集合中返回客户列表,并根据客户的位置对其进行分组。
' Obtain a list of customers.
Dim customers As List(Of Customer) = GetCustomers()
' Return customers that are grouped based on country.
Dim countries = From cust In customers
Order By cust.Country, cust.City
Group By CountryName = cust.Country
Into CustomersInCountry = Group, Count()
Order By CountryName
' Output the results.
For Each country In countries
Debug.WriteLine(country.CountryName & " count=" & country.Count)
For Each customer In country.CustomersInCountry
Debug.WriteLine(" " & customer.CompanyName & " " & customer.City)
Next
Next
' Output:
' Canada count=2
' Contoso, Ltd Halifax
' Fabrikam, Inc. Vancouver
' United States count=1
' Margie's Travel Redmond
运行示例
若要在简介和 LINQ 查询 的结构部分运行示例,请包括以下代码,该代码返回客户列表和订单列表。
' Return a list of customers.
Private Function GetCustomers() As List(Of Customer)
Return New List(Of Customer) From
{
New Customer With {.CustomerID = 1, .CompanyName = "Contoso, Ltd", .City = "Halifax", .Country = "Canada"},
New Customer With {.CustomerID = 2, .CompanyName = "Margie's Travel", .City = "Redmond", .Country = "United States"},
New Customer With {.CustomerID = 3, .CompanyName = "Fabrikam, Inc.", .City = "Vancouver", .Country = "Canada"}
}
End Function
' Return a list of orders.
Private Function GetOrders() As List(Of Order)
Return New List(Of Order) From
{
New Order With {.CustomerID = 1, .Amount = "200.00"},
New Order With {.CustomerID = 3, .Amount = "600.00"},
New Order With {.CustomerID = 1, .Amount = "300.00"},
New Order With {.CustomerID = 2, .Amount = "100.00"},
New Order With {.CustomerID = 3, .Amount = "800.00"}
}
End Function
' Customer Class.
Private Class Customer
Public Property CustomerID As Integer
Public Property CompanyName As String
Public Property City As String
Public Property Country As String
End Class
' Order Class.
Private Class Order
Public Property CustomerID As Integer
Public Property Amount As Decimal
End Class
LINQ 提供程序
LINQ 提供程序将 Visual Basic LINQ 查询映射到正在查询的数据源。 编写 LINQ 查询时,提供程序会获取该查询,并将其转换为数据源将能够执行的命令。 提供程序还会将数据从源转换为构成查询结果的对象。 最后,在向数据源发送更新时,它将对象转换为数据。
Visual Basic 包含以下 LINQ 提供程序。
提供者 | DESCRIPTION |
---|---|
LINQ to 对象 | LINQ to Objects 提供程序使你能够查询内存中集合和数组。 如果对象支持 IEnumerable 或 IEnumerable<T> 接口,则 LINQ to Objects 提供程序使你能够对其进行查询。 可以通过导入 System.Linq 命名空间来启用 LINQ to Objects 提供程序,该命名空间在所有 Visual Basic 项目中默认导入。 有关 LINQ to Objects 提供程序的详细信息,请参阅 LINQ to Objects。 |
LINQ to SQL | LINQ to SQL 提供程序使你能够查询和修改 SQL Server 数据库中的数据。 这样可以轻松地将应用程序的对象模型映射到数据库中的表和对象。 通过包括对象关系设计器(O/R 设计器),Visual Basic 可以更轻松地使用 LINQ to SQL。 此设计器用于在映射到数据库中对象的应用程序中创建对象模型。 O/R 设计器还提供将存储过程和函数映射到 DataContext 对象的功能,该对象管理与数据库的通信,并存储乐观并发检查的状态。 有关 LINQ to SQL 提供程序的详细信息,请参阅 LINQ to SQL。 有关对象关系设计器的详细信息,请参阅 Visual Studio 中的 LINQ to SQL 工具。 |
LINQ to XML | LINQ to XML 提供程序使你能够查询和修改 XML。 可以修改内存中 XML,也可以从文件中加载 XML 并将 XML 保存到文件中。 此外,LINQ to XML 提供程序还启用 XML 文本和 XML 轴属性,使你能够直接在 Visual Basic 代码中编写 XML。 有关详细信息,请参阅 XML。 |
LINQ to DataSet | LINQ to DataSet 提供程序使你能够查询和更新 ADO.NET 数据集中的数据。 可以将 LINQ 的功能添加到使用数据集的应用程序,以便简化和扩展查询、聚合和更新数据集中的数据的功能。 有关详细信息,请参阅 LINQ to DataSet。 |
LINQ 查询的结构
LINQ 查询(通常称为 查询表达式)包含用于标识查询数据源和迭代变量的查询子句的组合。 查询表达式还可以包含用于对源数据应用的排序、筛选、分组和联接或计算的说明。 查询表达式语法类似于 SQL 的语法;因此,你可能会发现许多熟悉的语法。
查询表达式以From
子句开头。 此子句标识查询的源数据和用于单独引用源数据的每个元素的变量。 这些变量命名为 范围变量 或 迭代变量。
From
子句是查询所必需的,但 Aggregate
查询除外,在该查询中 From
子句是可选的。 在From
或Aggregate
子句中标识查询的范围和源后,可以包含查询子句的任意组合来改进查询。 有关查询子句的详细信息,请参阅本主题后面的 Visual Basic LINQ 查询运算符。 例如,以下查询将客户数据的源集合标识为 customers
变量,以及一个名为 cust
的迭代变量。
Dim customers = GetCustomers()
Dim queryResults = From cust In customers
For Each result In queryResults
Debug.WriteLine(result.CompanyName & " " & result.Country)
Next
' Output:
' Contoso, Ltd Canada
' Margie's Travel United States
' Fabrikam, Inc. Canada
此示例本身是有效的查询;但是,添加更多查询子句以优化结果时,查询将变得更加强大。 例如,可以添加子 Where
句以按一个或多个值筛选结果。 查询表达式是一行代码;只需将其他查询子句追加到查询末尾。 可以使用下划线 (_) 行延续字符跨多行文本拆分查询以提高可读性。 下面的代码示例演示包含 Where
子句的查询示例。
Dim queryResults = From cust In customers
Where cust.Country = "Canada"
另一个功能强大的查询子句是 Select
子句,它使你只能从数据源返回选定的字段。 LINQ 查询返回强类型化对象的可枚举集合。 查询可以返回匿名类型或命名类型的集合。 可以使用子 Select
句仅返回数据源中的单个字段。 执行此作时,返回的集合的类型是该单个字段的类型。 还可以使用该 Select
子句从数据源返回多个字段。 执行此作时,返回的集合的类型是新的匿名类型。 还可以将查询返回的字段与指定命名类型的字段匹配。 下面的代码示例演示了一个查询表达式,该表达式返回一组匿名类型,这些匿名类型包含来自数据源中选定字段的数据。
Dim queryResults = From cust In customers
Where cust.Country = "Canada"
Select cust.CompanyName, cust.Country
LINQ 查询还可用于合并多个数据源并返回单个结果。 这可以通过一个或多个 From
子句完成,也可以使用 Join
或 Group Join
查询子句来完成。 下面的代码示例演示了一个查询表达式,该表达式合并了客户和订单数据,并返回包含客户和订单数据的匿名类型的集合。
Dim customers = GetCustomers()
Dim orders = GetOrders()
Dim queryResults = From cust In customers, ord In orders
Where cust.CustomerID = ord.CustomerID
Select cust, ord
For Each result In queryResults
Debug.WriteLine(result.ord.Amount & " " & result.ord.CustomerID & " " & result.cust.CompanyName)
Next
' Output:
' 200.00 1 Contoso, Ltd
' 300.00 1 Contoso, Ltd
' 100.00 2 Margie's Travel
' 600.00 3 Fabrikam, Inc.
' 800.00 3 Fabrikam, Inc.
可以使用子 Group Join
句创建包含客户对象的集合的分层查询结果。 每个客户对象都有一个属性,该属性包含该客户的所有订单集合。 下面的代码示例演示了一个查询表达式,该表达式将客户和订单数据合并为分层结果,并返回匿名类型的集合。 查询返回一个类型,该类型包含一个 CustomerOrders
属性,该属性包含客户的订单数据集合。 它还包括一个 OrderTotal
属性,该属性包含该客户的所有订单的总和。 (此查询等效于 LEFT OUTER JOIN。)
Dim customers = GetCustomers()
Dim orders = GetOrders()
Dim queryResults = From cust In customers
Group Join ord In orders On
cust.CustomerID Equals ord.CustomerID
Into CustomerOrders = Group,
OrderTotal = Sum(ord.Amount)
Select cust.CompanyName, cust.CustomerID,
CustomerOrders, OrderTotal
For Each result In queryResults
Debug.WriteLine(result.OrderTotal & " " & result.CustomerID & " " & result.CompanyName)
For Each ordResult In result.CustomerOrders
Debug.WriteLine(" " & ordResult.Amount)
Next
Next
' Output:
' 500.00 1 Contoso, Ltd
' 200.00
' 300.00
' 100.00 2 Margie's Travel
' 100.00
' 1400.00 3 Fabrikam, Inc.
' 600.00
' 800.00
可以使用其他几个 LINQ 查询运算符来创建功能强大的查询表达式。 本主题的下一部分讨论可在查询表达式中包含的各种查询子句。 有关 Visual Basic 查询子句的详细信息,请参阅 “查询”。
Visual Basic LINQ 查询运算符
命名空间中的 System.Linq 类和支持 LINQ 查询的其他命名空间包括可以调用的方法,以便根据应用程序的需求创建和优化查询。 Visual Basic 包括以下常见查询子句的关键字。 有关 Visual Basic 查询子句的详细信息,请参阅 “查询”。
From 子句
要开始查询,必须有From
子句或Aggregate
子句。 子 From
句指定查询的源集合和迭代变量。 例如:
' Returns the company name for all customers for which
' the Country is equal to "Canada".
Dim names = From cust In customers
Where cust.Country = "Canada"
Select cust.CompanyName
Select 子句
可选。 一个Select
子句为查询声明了一组迭代变量。 例如:
' Returns the company name and ID value for each
' customer as a collection of a new anonymous type.
Dim customerList = From cust In customers
Select cust.CompanyName, cust.CustomerID
如果未指定Select
子句,则查询的迭代变量由From
或Aggregate
子句指定的迭代变量组成。
Where 子句
可选。
Where
子句指定查询的筛选条件。 例如:
' Returns all product names for which the Category of
' the product is "Beverages".
Dim names = From product In products
Where product.Category = "Beverages"
Select product.Name
Order By 子句
可选。
Order By
子句指定查询中列的排列顺序。 例如:
' Returns a list of books sorted by price in
' ascending order.
Dim titlesAscendingPrice = From b In books
Order By b.price
Join 子句
可选。
Join
子句将两个集合合并为单个集合。 例如:
' Returns a combined collection of all of the
' processes currently running and a descriptive
' name for the process taken from a list of
' descriptive names.
Dim processes = From proc In Process.GetProcesses
Join desc In processDescriptions
On proc.ProcessName Equals desc.ProcessName
Select proc.ProcessName, proc.Id, desc.Description
Group By 子句
可选。
Group By
子句对查询结果的元素进行分组。 它可用于将聚合函数应用于每个组。 例如:
' Returns a list of orders grouped by the order date
' and sorted in ascending order by the order date.
Dim orderList = From order In orders
Order By order.OrderDate
Group By OrderDate = order.OrderDate
Into OrdersByDate = Group
Group Join 子句
可选。 一个Group Join
条款将两个集合合并为单个分层集合。 例如:
' Returns a combined collection of customers and
' customer orders.
Dim customerList = From cust In customers
Group Join ord In orders On
cust.CustomerID Equals ord.CustomerID
Into CustomerOrders = Group,
TotalOfOrders = Sum(ord.Amount)
Select cust.CompanyName, cust.CustomerID,
CustomerOrders, TotalOfOrders
Aggregate 子句
需要 Aggregate
子句 或 From
子句才能开始查询。
Aggregate
子句将一个或多个聚合函数应用于一个集合。 例如,可以使用 Aggregate
子句计算查询返回的所有元素的总和,如以下示例所示。
' Returns the sum of all order amounts.
Dim orderTotal = Aggregate order In orders
Into Sum(order.Amount)
还可以使用 Aggregate
子句修改查询。 例如,可以使用 Aggregate
子句对相关查询集合执行计算。 例如:
' Returns the customer company name and largest
' order amount for each customer.
Dim customerMax = From cust In customers
Aggregate order In cust.Orders
Into MaxOrder = Max(order.Amount)
Select cust.CompanyName, MaxOrder
Let 子句
可选。
Let
子句计算一个值,并将其分配到查询中的新变量。 例如:
' Returns a list of products with a calculation of
' a ten percent discount.
Dim discountedProducts = From prod In products
Let Discount = prod.UnitPrice * 0.1
Where Discount >= 50
Select prod.Name, prod.UnitPrice, Discount
Distinct 子句
可选。 子 Distinct
句限制当前迭代变量的值,以消除查询结果中的重复值。 例如:
' Returns a list of cities with no duplicate entries.
Dim cities = From item In customers
Select item.City
Distinct
Skip 子句
可选。
Skip
子句绕过集合中指定数量的元素,然后返回剩余的元素。 例如:
' Returns a list of customers. The first 10 customers
' are ignored and the remaining customers are
' returned.
Dim customerList = From cust In customers
Skip 10
Skip While 子句
可选。
Skip While
只要指定条件是true
,子句将绕过集合中的元素,然后返回其余元素。 例如:
' Returns a list of customers. The query ignores all
' customers until the first customer for whom
' IsSubscriber returns false. That customer and all
' remaining customers are returned.
Dim customerList = From cust In customers
Skip While IsSubscriber(cust)
Take 子句
可选。
Take
子句从集合的开头返回指定数量的连续元素。 例如:
' Returns the first 10 customers.
Dim customerList = From cust In customers
Take 10
Take While 子句
可选。 只要指定条件是Take While
并绕过其余元素,子true
就包括集合中的元素。 例如:
' Returns a list of customers. The query returns
' customers until the first customer for whom
' HasOrders returns false. That customer and all
' remaining customers are ignored.
Dim customersWithOrders = From cust In customers
Order By cust.Orders.Count Descending
Take While HasOrders(cust)
使用其他 LINQ 查询功能
可以通过调用 LINQ 提供的可枚举和可查询类型的成员来使用其他 LINQ 查询功能。 可以通过对查询表达式的结果调用特定查询运算符来使用这些附加功能。 例如,以下示例使用 Enumerable.Union 该方法将两个查询的结果合并为一个查询结果。 它使用 Enumerable.ToList 该方法将查询结果作为泛型列表返回。
Public Function GetAllCustomers() As List(Of Customer)
Dim customers1 = From cust In domesticCustomers
Dim customers2 = From cust In internationalCustomers
Dim customerList = customers1.Union(customers2)
Return customerList.ToList()
End Function
有关其他 LINQ 功能的详细信息,请参阅 标准查询运算符概述。
使用 LINQ to SQL 连接到数据库
在 Visual Basic 中,可以标识想要使用 LINQ to SQL 文件访问的 SQL Server 数据库对象,例如表、视图和存储过程。 LINQ to SQL 文件扩展名为 .dbml。
与 SQL Server 数据库建立有效连接时,可以向项目添加 LINQ to SQL 类 项目模板。 这将显示对象关系设计器(O/R 设计器)。 使用 O/R 设计器,可以将要在代码中访问的项从 服务器资源管理器/数据库资源管理器 拖动到设计器图面上。 LINQ to SQL 文件将对象 DataContext 添加到项目。 此对象包括要访问的表和视图的属性和集合,以及要调用的存储过程的方法。 将更改保存到 LINQ to SQL (.dbml) 文件后,可以通过引用 DataContext O/R 设计器定义的对象来访问代码中的这些对象。 项目的 DataContext 对象根据 LINQ to SQL 文件的名称进行命名。 例如,名为 Northwind.dbml 的 LINQ to SQL 文件将创建一个名为 DataContext 的NorthwindDataContext
对象。
有关分步说明的示例,请参阅 How to: Query a Database and How to: Call a Stored Procedure.
支持 LINQ 的 Visual Basic 功能
Visual Basic 包括其他值得注意的功能,这些功能使 LINQ 变得简单,并减少执行 LINQ 查询时必须编写的代码量。 其中包括:
匿名类型,使你能够基于查询结果创建新类型。
隐式类型化变量,使你能够延迟指定类型,并允许编译器根据查询结果推断类型。
扩展方法,使你能够使用自己的方法扩展现有类型,而无需修改类型本身。
有关详细信息,请参阅 支持 LINQ 的 Visual Basic 功能。
延迟执行和立即执行查询
查询执行与创建查询不同。 创建查询后,其执行由单独的机制触发。 只要定义查询(立即执行),就可以执行查询,也可以存储该定义,并且可以稍后执行查询(延迟执行)。
默认情况下,创建查询时,查询本身不会立即执行。 相反,查询定义存储在用于引用查询结果的变量中。 稍后在代码(如循环中 For…Next
)访问查询结果变量时,将执行查询。 此过程称为 延迟执行。
还可以在定义查询时执行查询,这称为 立即执行。 可以通过应用需要访问查询结果的各个元素的方法来触发立即执行。 这可以是包括聚合函数(如 Count
、 Sum
、 Average
、 Min
或 Max
)的结果。 有关聚合函数的详细信息,请参阅 Aggregate 子句。
使用 ToList
或 ToArray
方法也会强制立即执行。 如果要立即执行查询并缓存结果,这非常有用。 有关这些方法的详细信息,请参阅 “转换数据类型”。
有关查询执行的详细信息,请参阅 编写第一个 LINQ 查询。
Visual Basic 中的 XML
Visual Basic 中的 XML 功能包括 XML 文本和 XML 轴属性,使你可以轻松地在代码中创建、访问、查询和修改 XML。 XML 文本使你能够直接在代码中编写 XML。 Visual Basic 编译器将 XML 视为一流的数据对象。
下面的代码示例演示如何创建 XML 元素、访问其子元素和属性,以及使用 LINQ 查询元素的内容。
' Place Imports statements at the top of your program.
Imports <xmlns:ns="http://SomeNamespace">
Module Sample1
Sub SampleTransform()
' Create test by using a global XML namespace prefix.
Dim contact =
<ns:contact>
<ns:name>Patrick Hines</ns:name>
<ns:phone ns:type="home">206-555-0144</ns:phone>
<ns:phone ns:type="work">425-555-0145</ns:phone>
</ns:contact>
Dim phoneTypes =
<phoneTypes>
<%= From phone In contact.<ns:phone>
Select <type><%= phone.@ns:type %></type>
%>
</phoneTypes>
Console.WriteLine(phoneTypes)
End Sub
End Module
有关详细信息,请参阅 XML。
相关资源
主题 | DESCRIPTION |
---|---|
XML | 介绍 Visual Basic 中可以查询的 XML 功能,使你可以将 XML 作为一流数据对象包含在 Visual Basic 代码中。 |
查询 | 提供有关 Visual Basic 中提供的查询子句的参考信息。 |
LINQ(语言集成查询) | 包括 LINQ 的常规信息、编程指南和示例。 |
LINQ 到 SQL | 包括 LINQ to SQL 的常规信息、编程指南和示例。 |
LINQ to 对象 | 包括 LINQ to Objects 的常规信息、编程指南和示例。 |
LINQ to ADO.NET (门户页) | 包括 LINQ to ADO.NET 的常规信息、编程指南和示例的链接。 |
LINQ to XML | 包括 LINQ to XML 的常规信息、编程指南和示例。 |
“操作说明”和“演练”主题
特色书籍章节
第 17 章:Visual Basic 2008 编程中的 LINQ