Знакомство с LINQ в Visual Basic

Интегрированный с языком запрос (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 сопоставляет запросы LINQ Visual Basic с запрашиваемого источника данных. При написании запроса LINQ поставщик принимает запрос и переводит его в команды, которые источник данных будет способен выполнить. Затем поставщик преобразует данные из источника в объекты, составляющие результат запроса. И, наконец, при отправке обновлений на источник данных он преобразует объекты в данные.

Visual Basic включает следующие поставщики LINQ.

Provider Description
LINQ to Objects Поставщик LINQ to Objects позволяет направлять запросы к коллекциям и массивам, которые находятся в памяти. Если объект поддерживает интерфейс IEnumerable или IEnumerable<T>, поставщик LINQ to Objects позволяет направлять к нему запросы.

Вы можете включить поставщик объектов LINQ to Objects, импортируя System.Linq пространство имен, импортируемое по умолчанию для всех проектов Visual Basic.

Дополнительные сведения о поставщике объектов LINQ to Objects см. в разделе LINQ to Objects.
LINQ to SQL Поставщик LINQ to SQL позволяет запрашивать и изменять данные в базе данных SQL Server. Это упрощает сопоставление объектной модели приложения с таблицами и объектами в базе данных.

Visual Basic упрощает работу с LINQ to SQL, включая реляционный конструктор объектов (конструктор O/R). Он используется для создания в приложении модели объекта, которая сопоставляется с объектами в базе данных. Конструктор O/R также предоставляет функции для сопоставления хранимых процедур и функций с DataContext объектом, который управляет взаимодействием с базой данных и сохраняет состояние для оптимистических проверка параллелизма.

Дополнительные сведения о поставщике LINQ to SQL см. в разделе LINQ to SQL. Дополнительные сведения о реляционный конструктор объектов см. в статье LINQ to SQL Tools в Visual Studio.
LINQ to XML Поставщик LINQ to XML позволяет запрашивать и изменять XML. XML можно изменить в памяти, загрузить из файла и сохранить в файл.

Кроме того, поставщик LINQ to XML позволяет xml-литералы и свойства оси XML, позволяющие записывать 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 Query Operators далее в этом разделе. Например, следующий запрос определяет исходную коллекцию данных клиента как переменную 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 (в частности, System.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 вы определяете объекты базы данных SQL Server, такие как таблицы, представления и хранимые процедуры, к которым требуется получить доступ с помощью LINQ to SQL-файла. Файл LINQ to SQL имеет расширение DBML.

При наличии допустимого подключения к базе данных SQL Server в проект можно добавить шаблон элемента LINQ to SQL Classes . Это позволит отобразить реляционный конструктор объектов (O/R-конструктор). Конструктор O/R позволяет перетаскивать элементы, к которым вы хотите получить доступ в коде, с сервера Обозреватель Database Обозреватель/ на область конструктора. Файл LINQ to SQL добавляет в проект объект DataContext. Этот объект включает свойства и коллекции для таблиц и представлений, к которым нужно получить доступ, а также необходимые методы для хранимых процедур. После сохранения изменений в файле LINQ to SQL (DBML) можно получить доступ к этим объектам в коде, обратившись к определенному O/R-конструктором объекту DataContext. Объекту DataContext для проекта присваивается имя, которое определяется именем файла LINQ to SQL. Например, файл LINQ to SQL с именем Northwind.dbml создаст объект DataContext с именем NorthwindDataContext.

Примеры с пошаговыми инструкциями см. в статье "Практическое руководство. Запрос базы данных и практическое руководство. Вызов хранимой процедуры".

Функции Visual Basic, поддерживающие LINQ

Visual Basic включает другие важные функции, которые упрощают использование LINQ и сокращают объем кода, который необходимо записать для выполнения запросов LINQ. следующие основные параметры.

  • Анонимные типы, позволяющие создать новый тип на основе результата запроса.

  • Неявно типизированные переменные, позволяющие отложить указание типа и разрешить компилятору определить тип на основе результата запроса.

  • Методы расширения, позволяющие расширить существующий тип с собственными методами без изменения самого типа.

Дополнительные сведения см. в разделе "Функции Visual Basic", поддерживающие LINQ.

Отложенное и немедленное выполнение запросов

Процессы выполнения и создания запросов разделены. После создания запроса его выполнение инициируется отдельным механизмом. Запрос можно выполнить, как только он определен (немедленное выполнение), или определение может храниться, и запрос можно выполнить позже (отложенное выполнение).

По умолчанию вновь созданный запрос автоматически не выполняется. Вместо этого определение запроса сохраняется в переменной, которая используется для ссылки на результат этого запроса. Если впоследствии код обращается к переменной результата запроса, например в рамках цикла For…Next, запрос выполняется. Этот процесс называется отложенным выполнением.

Запросы также могут выполняться при определении, который называется немедленным выполнением. Немедленное выполнение можно инициировать с помощью метода, который требует доступа к отдельным элементам результата запроса. Это может быть результатом использования агрегатных функций, таких как Count, Sum, Average, Min или Max. Дополнительные сведения об агрегатных функциях см. в предложении Агрегата.

Принудительно вызвать немедленное выполнение запросов позволяют также методы ToList и ToArray. Это пригодится в том случае, если требуется выполнить запрос немедленно и кэшировать результаты. Дополнительные сведения об этих методах см. в разделе "Преобразование типов данных".

Дополнительные сведения о выполнении запросов см. в статье "Написание первого запроса LINQ".

XML в Visual Basic

Функции XML в Visual Basic включают 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.

Раздел Описание
XML Описывает функции XML в Visual Basic, которые можно запрашивать и которые позволяют включать 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.

Инструкции и пошаговое руководство

How to: Query a Database (Практическое руководство. Выполнение запросов к базе данных)

How to: Call a Stored Procedure (Практическое руководство. Вызов хранимой процедуры)

How to: Modify Data in a Database (Практическое руководство. Изменение данных в базе данных)

How to: Combine Data with Joins (Практическое руководство. Объединение данных с помощью соединений)

How to: Sort Query Results (Практическое руководство. Сортировка результатов запроса)

How to: Filter Query Results (Практическое руководство. Фильтрование результатов запроса)

How to: Count, Sum, or Average Data (Практическое руководство. Выполнение функций Count, Sum и Average)

How to: Find the Minimum or Maximum Value in a Query Result (Практическое руководство. Нахождение минимального или максимального значения в результатах запроса)

Практическое руководство. Назначение хранимых процедур для выполнения обновления, вставки и удаления (реляционный конструктор объектов)

Глава 17. LINQ в программировании Visual Basic 2008

См. также