编写第一个 LINQ 查询 (Visual Basic)Writing Your First LINQ Query (Visual Basic)

查询是一种从数据源检索数据的表达式。A query is an expression that retrieves data from a data source. 查询以专用查询语言表示。Queries are expressed in a dedicated query language. 随着时间的推移,为不同类型的数据源开发了不同的语言,例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。Over time, different languages have been developed for different types of data sources, for example, SQL for relational databases and XQuery for XML. 这样,应用程序开发人员就可以为所支持的每种类型的数据源或数据格式学习一种新的查询语言。This makes it necessary for the application developer to learn a new query language for each type of data source or data format that is supported.

语言集成查询(LINQ)通过提供用于跨各种数据源和格式的数据的一致模型,简化了这种情况。Language-Integrated Query (LINQ) simplifies the situation by offering a consistent model for working with data across various kinds of data sources and formats. 在 LINQ 查询中,始终会用到对象。In a LINQ query, you are always working with objects. 您可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集和实体中的数据、.NET Framework 集合以及 LINQ 提供程序可用的任何其他源或格式。You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NET datasets and entities, .NET Framework collections, and any other source or format for which a LINQ provider is available. 本文档介绍了创建和使用基本 LINQ 查询的三个阶段。This document describes the three phases of the creation and use of basic LINQ queries.

查询操作的三个阶段Three Stages of a Query Operation

LINQ 查询操作包含三个操作:LINQ query operations consist of three actions:

  1. 获取数据源。Obtain the data source or sources.

  2. 创建查询。Create the query.

  3. 执行查询。Execute the query.

在 LINQ 中,查询的执行与查询的创建不同。In LINQ, the execution of a query is distinct from the creation of the query. 不只是通过创建查询来检索任何数据。You do not retrieve any data just by creating a query. 这一点将在本主题后面部分进行更详细的讨论。This point is discussed in more detail later in this topic.

下面的示例演示了查询操作的三个部分。The following example illustrates the three parts of a query operation. 为了便于演示,该示例使用一个整数数组作为方便的数据源。The example uses an array of integers as a convenient data source for demonstration purposes. 不过,相同的概念也适用于其他数据源。However, the same concepts also apply to other data sources.

备注

在 "编译" 页上的 "项目设计器" (Visual Basic)上,确保 "选项推断" 设置为 "开"On the Compile Page, Project Designer (Visual Basic), ensure that Option infer is set to On.

' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}

' Query creation.
Dim evensQuery = From num In numbers
                 Where num Mod 2 = 0
                 Select num

' Query execution.
For Each number In evensQuery
    Console.Write(number & " ")
Next

输出:Output:

0 2 4 6

数据源The Data Source

由于上一个示例中的数据源是一个数组,因此它隐式支持泛型 IEnumerable<T> 接口。Because the data source in the previous example is an array, it implicitly supports the generic IEnumerable<T> interface. 这种情况下,您可以使用数组作为 LINQ 查询的数据源。It is this fact that enables you to use an array as a data source for a LINQ query. 支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为可查询类型 。Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

作为隐式查询类型,数组不需要修改或特殊处理就可以用作 LINQ 数据源。As an implicitly queryable type, the array requires no modification or special treatment to serve as a LINQ data source. 对于支持的任何集合类型也是如此 IEnumerable<T> ,包括泛型 List<T>Dictionary<TKey,TValue> 和 .NET Framework 类库中的其他类。The same is true for any collection type that supports IEnumerable<T>, including the generic List<T>, Dictionary<TKey,TValue>, and other classes in the .NET Framework class library.

如果尚未实现源数据 IEnumerable<T> ,则需要 LINQ 提供程序来实现该数据源的标准查询运算符的功能。If the source data does not already implement IEnumerable<T>, a LINQ provider is needed to implement the functionality of the standard query operators for that data source. 例如, LINQ to XMLLINQ to XML 处理将 XML 文档加载到可查询类型的工作 XElement ,如下面的示例中所示。For example, LINQ to XMLLINQ to XML handles the work of loading an XML document into a queryable XElement type, as shown in the following example. 有关标准查询运算符的详细信息,请参阅标准查询运算符概述(Visual Basic)For more information about standard query operators, see Standard Query Operators Overview (Visual Basic).

' Create a data source from an XML document.
Dim contacts = XElement.Load("c:\myContactList.xml")

使用 LINQ to SQLLINQ to SQL ,你可以在设计时先使用 Visual studio 中的visual studio 中的 LINQ to SQL 工具来创建对象关系映射。With LINQ to SQLLINQ to SQL, you first create an object-relational mapping at design time, either manually or by using the LINQ to SQL Tools in Visual Studio in Visual Studio. 针对这些对象编写查询,然后由 LINQ to SQLLINQ to SQL 在运行时处理与数据库的通信。You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. 在下面的示例中, customers 表示数据库中的特定表,并 Table<TEntity> 支持泛型 IQueryable<T>In the following example, customers represents a specific table in the database, and Table<TEntity> supports generic IQueryable<T>.

' Create a data source from a SQL table.  
Dim db As New DataContext("C:\Northwind\Northwnd.mdf")  
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)  

有关如何创建特定类型的数据源的详细信息,请参阅各种 LINQ 提供程序的文档。For more information about how to create specific types of data sources, see the documentation for the various LINQ providers. (有关这些提供程序的列表,请参阅LINQ (语言集成查询)。)基本规则非常简单: LINQ 数据源是支持泛型接口的任何对象 IEnumerable<T> ,或者是从该接口继承的接口。(For a list of these providers, see LINQ (Language-Integrated Query).) The basic rule is simple: a LINQ data source is any object that supports the generic IEnumerable<T> interface, or an interface that inherits from it.

备注

ArrayList支持非泛型接口的类型(如) IEnumerable 也可用作 LINQ 数据源。Types such as ArrayList that support the non-generic IEnumerable interface can also be used as LINQ data sources. 有关使用的示例 ArrayList ,请参阅如何:使用 LINQ 查询 ArrayList (Visual Basic)For an example that uses an ArrayList, see How to: Query an ArrayList with LINQ (Visual Basic).

查询The Query

在查询中,可以指定要从数据源中检索的信息。In the query, you specify what information you want to retrieve from the data source or sources. 您还可以选择在返回信息之前如何对其进行排序、分组或结构化。You also have the option of specifying how that information should be sorted, grouped, or structured before it is returned. 若要启用查询创建,Visual Basic 已将新的查询语法合并到语言中。To enable query creation, Visual Basic has incorporated new query syntax into the language.

执行时,以下示例中的查询将从整数数组中返回所有偶数 numbersWhen it is executed, the query in the following example returns all the even numbers from an integer array, numbers.

' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}

' Query creation.
Dim evensQuery = From num In numbers
                 Where num Mod 2 = 0
                 Select num

' Query execution.
For Each number In evensQuery
    Console.Write(number & " ")
Next

查询表达式包含三个子句: FromWhereSelectThe query expression contains three clauses: From, Where, and Select. 基本查询操作(Visual Basic)中讨论了每个查询表达式子句的特定函数和目的。The specific function and purpose of each query expression clause is discussed in Basic Query Operations (Visual Basic). 有关详细信息,请参阅查询For more information, see Queries. 请注意,在 LINQ 中,查询定义通常存储在变量中,并在以后执行。Note that in LINQ, a query definition often is stored in a variable and executed later. 查询变量(如 evensQuery 前面的示例中的)必须是可查询的类型。The query variable, such as evensQuery in the previous example, must be a queryable type. 的类型 evensQueryIEnumerable(Of Integer) ,由编译器使用局部类型推理分配。The type of evensQuery is IEnumerable(Of Integer), assigned by the compiler using local type inference.

请记住,查询变量本身不会执行任何操作,也不会返回任何数据。It is important to remember that the query variable itself takes no action and returns no data. 它仅存储查询定义。It only stores the query definition. 在上面的示例中,它是 For Each 执行查询的循环。In the previous example, it is the For Each loop that executes the query.

查询执行Query Execution

查询执行与查询创建分离。Query execution is separate from query creation. 查询创建定义查询,但执行由不同的机制触发。Query creation defines the query, but execution is triggered by a different mechanism. 可在定义查询后立即执行查询(立即执行),也可以存储定义,并在以后执行查询(延迟执行)。A query can be executed as soon as it is defined (immediate execution), or the definition can be stored and the query can be executed later (deferred execution).

延迟执行Deferred Execution

典型 LINQ 查询类似于上一示例中定义的查询 evensQueryA typical LINQ query resembles the one in the previous example, in which evensQuery is defined. 它将创建查询,但不会立即执行。It creates the query but does not execute it immediately. 相反,查询定义存储在查询变量中 evensQueryInstead, the query definition is stored in the query variable evensQuery. 稍后,您将执行查询(通常通过使用 For Each 返回值序列的循环)或应用标准查询运算符(如 Count 或) MaxYou execute the query later, typically by using a For Each loop, which returns a sequence of values, or by applying a standard query operator, such as Count or Max. 此过程称为 "延迟执行"。This process is referred to as deferred execution.

' Query execution that results in a sequence of values.
For Each number In evensQuery
    Console.Write(number & " ")
Next

' Query execution that results in a single value.
Dim evens = evensQuery.Count()

对于值序列,可以使用 For Each 循环( number 在前面的示例中为)中的迭代变量来访问检索的数据。For a sequence of values, you access the retrieved data by using the iteration variable in the For Each loop (number in the previous example). 由于查询变量 evensQuery 包含查询定义,而不是查询结果,因此可以多次使用查询变量,按所需频率执行查询。Because the query variable, evensQuery, holds the query definition rather than the query results, you can execute a query as often as you want by using the query variable more than one time. 例如,你的应用程序中可能存在由单独的应用程序持续更新的数据库。For example, you might have a database in your application that is being updated continually by a separate application. 创建了从该数据库中检索数据的查询后,可以使用 For Each 循环重复执行该查询,每次检索最新的数据。After you have created a query that retrieves data from that database, you can use a For Each loop to execute the query repeatedly, retrieving the most recent data every time.

下面的示例演示延迟执行的工作方式。The following example demonstrates how deferred execution works. evensQuery2使用循环定义并执行后 For Each ,如前面的示例中所示,数据源中的某些元素 numbers 将发生更改。After evensQuery2 is defined and executed with a For Each loop, as in the previous examples, some elements in the data source numbers are changed. 然后 For Each 再次运行另一个循环 evensQuery2Then a second For Each loop runs evensQuery2 again. 由于 For Each 循环再次执行查询(使用中的新值),因此结果是不同的 numbersThe results are different the second time, because the For Each loop executes the query again, using the new values in numbers.

Dim numberArray() = {0, 1, 2, 3, 4, 5, 6}

Dim evensQuery2 = From num In numberArray
                  Where num Mod 2 = 0
                  Select num

Console.WriteLine("Evens in original array:")
For Each number In evensQuery2
    Console.Write("  " & number)
Next
Console.WriteLine()

' Change a few array elements.
numberArray(1) = 10
numberArray(4) = 22
numberArray(6) = 8

' Run the same query again.
Console.WriteLine(vbCrLf & "Evens in changed array:")
For Each number In evensQuery2
    Console.Write("  " & number)
Next
Console.WriteLine()

输出:Output:

Evens in original array:

0 2 4 6

Evens in changed array:

0 10 2 22 8

立即执行Immediate Execution

在延迟的查询执行中,查询定义存储在查询变量中以供以后执行。In deferred execution of queries, the query definition is stored in a query variable for later execution. 在 "立即执行" 中,将在定义时执行查询。In immediate execution, the query is executed at the time of its definition. 当应用需要访问查询结果的单个元素的方法时,将触发执行。Execution is triggered when you apply a method that requires access to individual elements of the query result. 通常,使用返回单个值的标准查询运算符之一来强制立即执行。Immediate execution often is forced by using one of the standard query operators that return single values. 例如, CountMax AverageFirstExamples are Count, Max, Average, and First. 这些标准查询运算符会在应用查询后立即执行查询,以便计算并返回单一实例结果。These standard query operators execute the query as soon as they are applied in order to calculate and return a singleton result. 有关返回单个值的标准查询运算符的详细信息,请参阅聚合运算元素操作限定符运算For more information about standard query operators that return single values, see Aggregation Operations, Element Operations, and Quantifier Operations.

下面的查询返回整数数组中偶数的计数。The following query returns a count of the even numbers in an array of integers. 查询定义不会保存, numEvens 这是一个简单的 IntegerThe query definition is not saved, and numEvens is a simple Integer.

Dim numEvens = (From num In numbers
                Where num Mod 2 = 0
                Select num).Count()

您可以通过使用方法获得相同的结果 AggregateYou can achieve the same result by using the Aggregate method.

Dim numEvensAgg = Aggregate num In numbers
                  Where num Mod 2 = 0
                  Select num
                  Into Count()

您还可以通过 ToList ToArray 对查询(直属)或查询变量(延迟)调用或方法来强制执行查询,如下面的代码所示。You can also force execution of a query by calling the ToList or ToArray method on a query (immediate) or query variable (deferred), as shown in the following code.

' Immediate execution.
Dim evensList = (From num In numbers
                 Where num Mod 2 = 0
                 Select num).ToList()

' Deferred execution.
Dim evensQuery3 = From num In numbers
                  Where num Mod 2 = 0
                  Select num
' . . .
Dim evensArray = evensQuery3.ToArray()

在前面的示例中, evensQuery3 是一个查询变量,但 evensList 是一个列表, evensArray 是一个数组。In the previous examples, evensQuery3 is a query variable, but evensList is a list and evensArray is an array.

ToList ToArray 如果希望立即执行查询并将结果缓存在单个集合对象中,则使用或强制立即执行将特别有用。Using ToList or ToArray to force immediate execution is especially useful in scenarios in which you want to execute the query immediately and cache the results in a single collection object. 有关这些方法的详细信息,请参阅转换数据类型For more information about these methods, see Converting Data Types.

您还可以使用 IEnumerable 方法(如方法)来执行查询 IEnumerable.GetEnumeratorYou can also cause a query to be executed by using an IEnumerable method such as the IEnumerable.GetEnumerator method.

另请参阅See also