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

Language-Integrated Query (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.

Поставщик Описание
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 также предоставляет функциональные возможности для сопоставления хранимых процедур и функций с 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 далее в этом разделе. Например, следующий запрос определяет исходную коллекцию данных клиента как переменную 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-конструктор). Конструктор объектов ввода-вывода позволяет перетаскивать элементы, к которым вы хотите получить доступ в коде, из обозревателя ServerExplorerDatabase/ в область конструктора. Файл 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. Дополнительные сведения о агрегатных функциях см. в предложении Aggregate.

Принудительно вызвать немедленное выполнение запросов позволяют также методы 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

См. также раздел