Visual Basic 中的 LINQ 简介

更新:2007 年 11 月

语言集成查询 (LINQ) 为 Visual Basic 添加了查询功能,并且提供了用于处理各种数据的简单而强大的功能。LINQ 引入查询作为 Visual Basic 语言的一部分,而不是向数据库发送要进行处理的查询,或者对要搜索的每种类型的数据使用不同的查询语法。它使用与数据类型无关的统一语法。

使用 LINQ 可以从 SQL Server 数据库、XML、内存中数组和集合、ADO.NET 数据集或任何其他支持 LINQ 的远程或本地数据源查询数据。利用常见的 Visual Basic 语言元素即可执行上述所有操作。因为查询是用 Visual Basic 语言编写的,所以查询结果以强类型对象的形式返回。这些对象支持 IntelliSense,后者使您可以更快地编写代码,并且在编译时而不是运行时捕捉查询中的错误。LINQ 查询可用作其他查询的源,以优化查询结果。还可以将这些查询绑定到控件,以便用户可以轻松地查看和修改查询结果。

例如,下面的代码示例演示一个 LINQ 查询,该查询从一个集合返回客户列表,并将这些客户按地点进行分组。

Dim customers As List(Of Customer) = GetCustomerList()

Dim customersByCountry = From cust In customers _
                         Order By cust.Country, cust.City _
                         Group By CountryName = cust.Country _
                         Into RegionalCustomers = Group, Count() _
                         Order By CountryName

For Each country In customersByCountry
  Console.WriteLine(country.CountryName & _
                    " (" & country.Count & ")" & vbCrLf)

  For Each customer In country.RegionalCustomers
    Console.WriteLine(vbTab & customer.CompanyName & _
                      " (" & customer.City & ")")
  Next
Next

在本主题中,您将了解有关以下领域的信息:

  • LINQ 提供程序

  • LINQ 查询的结构

  • Visual Basic LINQ 查询运算符

  • 使用 LINQ to SQL 连接到数据库

  • 支持 LINQ 的 Visual Basic 功能

  • 延迟执行查询和立即执行查询

  • Visual Basic 中的 XML

  • 相关资源

  • 帮助和演练主题

LINQ 提供程序

“LINQ 提供程序”将 Visual Basic LINQ 查询映射到要查询的数据源。编写 LINQ 查询时,提供程序接受该查询并将其转换为数据源能够执行的命令。提供程序还将源中的数据转换为组成查询结果的对象。最后,当您向数据源发送更新时,它能够将对象转换为数据。

Visual Basic 包含以下 LINQ 提供程序。

  • LINQ to Objects
    使用 LINQ to Objects 提供程序可以查询内存中的集合和数组。如果对象支持 IEnumerableIEnumerable<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 数据库中的数据。这样就可以轻松地将应用程序的对象模型映射到数据库中的表和对象。

    Visual Basic 通过包含对象关系设计器(O/R 设计器)使 LINQ to SQL 更加易于使用。此设计器用于在应用程序中创建映射到数据库中的对象的对象模型。O/R 设计器还提供了将存储过程和函数映射到 DataContext 对象的功能,该对象管理与数据库的通信,并存储开放式并发检查的状态。

    有关 LINQ to SQL 提供程序的更多信息,请参见 LINQ to SQL。有关对象关系设计器的更多信息,请参见对象关系设计器(O/R 设计器)

  • LINQ to XML
    使用 LINQ to XML 提供程序可以查询和修改 XML。您可以修改内存中的 XML,也可以从文件加载 XML 以及将 XML 保存到文件。

    此外,LINQ to XML 提供程序还支持 XML 文本属性和 XML 轴属性,使您能够直接在 Visual Basic 代码中编写 XML。有关更多信息,请参见 Visual Basic 中的 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 queryResults = From cust In customers _
                   Select cust.CompanyName

此示例本身即为一个有效查询;但当您添加更多查询子句以优化结果后,该查询的功能将变得强大许多。例如,可以添加一个 Where 子句按一个或多个值筛选结果。查询表达式是单行代码;您只能在查询末尾追加其他查询子句。使用下划线 (_) 行继续符可以将一个查询分为多行文本,以提高可读性。下面的代码示例演示包含一个 Where 子句的查询示例。

Dim queryResults = From cust In customers _
                   Where cust.Country = "USA"

另一个功能强大的查询子句是 Select 子句,使用该子句可以从数据源仅返回选定的字段。LINQ 查询返回可枚举的强类型对象集合。查询可以返回匿名类型或命名类型的集合。使用 Select 子句可以从数据源仅返回单个字段。如果您这样做,返回的集合的类型将是该字段的类型。使用 Select 子句也可以从数据源返回多个字段。如果您这样做,返回的集合的类型将是一个新的匿名类型。还可以将查询所返回的字段与指定的命名类型的字段进行匹配。下面的代码示例演示一个查询表达式,该表达式返回一个匿名类型集合,其成员用数据源中选定字段的数据进行填充。

Dim queryResults = From cust In customers _
               Where cust.Country = "USA" _
               Select cust.CompanyName, cust.Country

LINQ 查询还可以用于组合多个数据源并返回单个结果。这可以通过一个或多个 From 子句,或者通过使用 Join 或 Group Join 查询子句来实现。下面的代码示例演示一个查询表达式,该表达式将客户和订单数据组合在一起,并返回包含客户和订单数据的匿名类型的集合。

Dim queryResults = From cust In customers, ord In orders _
                   Where cust.CustomerID = ord.CustomerID _
                   Select cust, ord

使用 Group Join 子句可以创建包含客户对象集合的分层查询结果。每个客户对象都具有一个属性,该属性包含该客户所有订单的集合。下面的代码示例演示一个查询表达式,该表达式将客户和订单数据组合为分层结果,并返回一个匿名类型集合。该查询返回一个包含 CustomerOrders 属性的类型,该属性包含该客户的订单数据集合。该类型还包含一个 OrderTotal 属性,该属性包含该客户的所有订单总额之和。(此查询等效于一个“左外部联接”。)

Dim queryResults = From cust In customers _
                   Group Join ord In orders On _
                     cust.CustomerID Equals ord.CustomerID _
                     Into CustomerOrders = Group, _
                          OrderTotal = Sum(ord.Total) _
                   Select cust.CompanyName, cust.CustomerID, _
                          CustomerOrders, OrderTotal

您还可以使用其他几个 LINQ 查询运算符来创建功能强大的查询表达式。本主题的下一部分讨论可以包含在查询表达式中的各种查询子句。有关 Visual Basic 查询子句的详细信息,请参见查询 (Visual Basic)

Visual Basic LINQ 查询运算符

System.Linq 命名空间和其他支持 LINQ 查询的命名空间中的类包含一些方法,您可以根据应用程序的需要,调用这些方法以创建和优化查询。Visual Basic 包含最常见查询子句的关键字,如下表所述。

  • From 子句 (Visual Basic)
    需要使用 From 子句或 Aggregate 子句以开始查询。From 子句为查询指定源集合和迭代变量。例如:

    ' Returns the company name for all customers for whom
    ' State is equal to "WA".
    Dim names = From cust In customers _
                Where cust.State = "WA" _
                Select cust.CompanyName
    
  • Select 子句 (Visual Basic)
    可选。为查询声明一组迭代变量。例如:

    ' 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 子句 (Visual Basic)
    可选。指定查询的筛选条件。例如:

    ' 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 子句 (Visual Basic)
    可选。指定查询中列的排序顺序。例如:

    ' Returns a list of books sorted by price in 
    ' ascending order.
    Dim titlesAscendingPrice = From b In books _
                               Order By b.price
    
  • Join 子句 (Visual Basic)
    可选。将两个集合组合为单个集合。例如:

    ' 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 子句 (Visual Basic)
    可选。对查询结果的元素进行分组。可用于将聚合函数应用于每个组。例如:

    ' 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 子句 (Visual Basic)
    可选。将两个集合组合为单个分层集合。例如:

    ' 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.Total) _
                       Select cust.CompanyName, cust.CustomerID, _
                              CustomerOrders, TotalOfOrders
    
  • Aggregate 子句 (Visual Basic)
    需要使用 From 子句或 Aggregate 子句以开始查询。Aggregate 子句对集合应用一个或多个聚合函数。例如,使用 Aggregate 子句可以计算查询返回的所有元素之和。

    ' Returns the sum of all order totals.
    Dim orderTotal = Aggregate order In orders _
                     Into Sum(order.Total)
    

    使用 Aggregate 子句还可以修改查询。例如,可以使用 Aggregate 子句对相关查询集合执行计算。

    ' Returns the customer company name and largest 
    ' order total for each customer.
    Dim customerMax = From cust In customers _
                      Aggregate order In cust.Orders _
                      Into MaxOrder = Max(order.Total) _
                      Select cust.CompanyName, MaxOrder
    
  • Let 子句 (Visual Basic)
    可选。计算一个值并将该值赋给查询中的新变量。例如:

    ' 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 子句 (Visual Basic)
    可选。对当前迭代变量的值进行限制以避免在查询结果中出现重复值。例如:

    ' Returns a list of cities with no duplicate entries.
    Dim cities = From item In customers _
                 Select item.City _
                 Distinct
    
  • Skip 子句 (Visual Basic)
    可选。跳过集合中指定数量的元素,然后返回剩余的元素。例如:

    ' 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 子句 (Visual Basic)
    可选。只要指定的条件为 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 子句 (Visual Basic)
    可选。从集合开始处起,返回指定数量的连续元素。例如:

    ' Returns the first 10 customers.
    Dim customerList = From cust In customers _
                       Take 10
    
  • Take While 子句 (Visual Basic)
    可选。只要指定的条件为 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)
    

有关 Visual Basic 查询子句的详细信息,请参见查询 (Visual Basic)

通过调用 LINQ 提供的可枚举且可查询类型的成员,可以使用其他 LINQ 查询功能。可以通过对查询表达式的结果调用特定查询运算符来使用这些附加功能。例如,下面的代码示例使用 Union 方法将两个查询的结果组合为一个查询结果。它使用 ToList<TSource> 方法以泛型列表的形式返回查询结果。

VbVbalrIntroToLINQ#22

有关其他 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) 文件后,可以通过引用 O/R 设计器所定义的 DataContext 对象,在代码中访问这些对象。项目的 DataContext 对象是根据 LINQ to SQL 文件的名称命名的。例如,名为 Northwind.dbml 的 LINQ to SQL 文件将创建一个名为 NorthwindDataContext 的 DataContext 对象。

有关分步说明的示例,请参见如何:使用 LINQ 查询数据库 (Visual Basic)如何:使用 LINQ 调用存储过程 (Visual Basic)

支持 LINQ 的 Visual Basic 功能

Visual Basic 包含其他一些值得注意的功能,这些功能可简化 LINQ 的使用并减少为执行 LINQ 查询而必须编写的代码数量。这些功能包括:

  • 匿名类型,使您能够根据查询结果创建新类型。

  • 隐式类型化变量,使您能够延迟指定类型,并使编译器可以根据查询结果推断类型。

  • 扩展方法,使您能够用自己的方法扩展现有类型,而无需修改类型本身

有关详细信息,请参见支持 LINQ 的 Visual Basic 功能

延迟执行查询和立即执行查询

查询执行与查询创建是分开的。创建查询后,其执行由不同的机制触发。可在定义查询后立即执行查询(“立即执行”),也可以存储查询定义,并在以后执行查询(“延迟执行”)。

默认情况下,创建查询后,查询本身并不立即执行。相反,查询定义将存储在用于引用查询结果的变量中。当以后在代码中访问查询结果变量时(例如在 For…Next 循环中),将执行该查询。此过程称为“延迟执行”。

查询还可以在定义后执行,这称为“立即执行”。立即执行可以通过应用要求访问查询结果的各个元素的方法来触发。这可能是包含聚合函数(例如,Count、Sum、Average、Min 或 Max)的结果。有关聚合函数的更多信息,请参见 Aggregate 子句 (Visual Basic)

使用 ToList 或 ToArray 方法也能够强制立即执行。当您希望立即执行查询并缓存结果时,此方法可能有用。有关这些方法的更多信息,请参见转换数据类型

有关查询执行的更多信息,请参见编写第一个 LINQ 查询 (Visual Basic)

Visual Basic 中的 XML

Visual Basic 中的 XML 功能包括 XML 文本和 XML 轴属性,使用这些属性可以在代码中轻松地创建、访问、查询和修改 XML。使用 XML 文本可以直接在代码中编写 XML。Visual Basic 编译器将 XML 视为一等数据对象。

下面的代码示例演示如何使用 LINQ 来创建一个 XML 元素,访问其子元素和属性,以及查询该元素的内容。

' 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

有关更多信息,请参见 Visual Basic 中的 XML

相关资源

  • Visual Basic 中的 XML
    介绍 Visual Basic 中的可以查询并可在 Visual Basic 代码中用来包含 XML 作为一级数据对象的 XML 功能。

  • 查询 (Visual Basic)
    提供有关 Visual Basic 中可用的查询子句的参考信息。

  • 语言集成查询 (LINQ)
    提供有关 LINQ 的一般信息、编程指南和示例。

  • LINQ to SQL
    提供有关 LINQ to SQL 的一般信息、编程指南和示例。

  • LINQ to Objects
    提供有关 LINQ to Objects 的一般信息、编程指南和示例。

  • LINQ to ADO.NET(门户页)
    提供一些链接,这些链接指向有关 LINQ to ADO.NET 的一般信息、编程指南和示例。

  • LINQ to XML
    提供有关 LINQ to XML 的一般信息、编程指南和示例。

帮助和演练主题

如何:使用 LINQ 查询数据库 (Visual Basic)

如何:使用 LINQ 调用存储过程 (Visual Basic)

如何:使用 LINQ 修改数据库中的数据 (Visual Basic)

如何:通过 LINQ 使用联接合并数据 (Visual Basic)

如何:使用 LINQ 对集合进行排序 (Visual Basic)

如何:使用 LINQ 筛选查询结果 (Visual Basic)

如何:使用 LINQ 对数据进行计数、求和与求平均值计算 (Visual Basic)

如何:使用 LINQ 查找查询结果中的最小值或最大值 (Visual Basic)

演练:创建 LINQ to SQL 类(O/R 设计器)

如何:指定存储过程以执行更新、插入和删除(O/R 设计器)

请参见

概念

Visual Basic 中的 LINQ to XML 概述

LINQ to DataSet 概述

DataContext 方法(O/R 设计器)

其他资源

语言集成查询 (LINQ)

LINQ to SQL

LINQ 示例

对象关系设计器(O/R 设计器)