Поделиться через


Запросы в LINQ to DataSet

Запрос — это выражение, которое извлекает данные из источника данных. Запросы обычно выражаются на специализированном языке запросов, например SQL для реляционных баз данных и XQuery для XML. Поэтому разработчикам пришлось узнать новый язык запросов для каждого типа источника данных или формата данных, который они запрашивают. Language-Integrated Query (LINQ) предлагает более простую и согласованную модель для работы с данными в различных типах источников данных и форматов. В запросе LINQ вы всегда работаете с программными объектами.

Операция запроса LINQ состоит из трех действий: получение источника данных или источников, создание запроса и выполнение запроса.

Источники данных, реализующие универсальный интерфейс IEnumerable<T>, можно запрашивать через LINQ. Вызов AsEnumerable в DataTable возвращает объект, реализующий универсальный интерфейс IEnumerable<T>, который служит источником данных для запросов LINQ to DataSet.

В запросе вы указываете именно сведения, которые требуется извлечь из источника данных. Запрос также может указать, как эти сведения должны быть отсортированы, сгруппированы и сформированы перед возвратом. В LINQ запрос хранится в переменной. Если запрос предназначен для возврата последовательности значений, сама переменная запроса должна быть перечисленным типом. Эта переменная запроса не принимает никаких действий и не возвращает данные; Он хранит только сведения о запросе. После создания запроса необходимо выполнить этот запрос, чтобы получить все данные.

В запросе, который возвращает последовательность значений, переменная запроса никогда не содержит результаты запроса и сохраняет только команды запроса. Выполнение запроса откладывается до тех пор, пока переменная запроса не будет итерирована в цикле foreach или For Each. Это называется отложенным выполнением; То есть выполнение запроса происходит некоторое время после создания запроса. Это означает, что вы можете выполнять запрос как можно чаще. Это полезно, например, если у вас есть база данных, обновляемая другими приложениями. В приложении можно создать запрос для получения последних сведений и многократного выполнения запроса, возвращая обновленные сведения каждый раз.

В отличие от отложенных запросов, возвращающих последовательность значений, запросы, возвращающие однотонное значение, выполняются немедленно. Ниже приведены некоторые примеры одноэлементных запросов: Count, Max, Averageи First. Они выполняются немедленно, так как результаты запроса необходимы для вычисления одноэлементного результата. Например, чтобы найти среднее значение результатов запроса, необходимо выполнить запрос, чтобы в средней функции были входные данные для работы. Вы также можете использовать методы ToList или ToArray в запросе, чтобы принудительно выполнить запрос, который не возвращает единственное значение. Эти методы принудительного выполнения могут быть полезны, если требуется кэшировать результаты запроса.

Запросы

Запросы LINQ to DataSet можно сформулировать в двух разных синтаксисах: синтаксис выражения запроса и синтаксис запросов на основе метода.

Синтаксис выражения запроса

Выражения запросов — это декларативный синтаксис запроса. Этот синтаксис позволяет разработчику писать запросы в C# или Visual Basic в формате, аналогичном SQL. С помощью синтаксиса выражения запроса можно выполнять даже сложные операции фильтрации, упорядочивания и группировки в источниках данных с минимальным кодом. Дополнительные сведения см. в выражениях запросов LINQ и базовых операций запросов (Visual Basic).

Среда CLR для .NET Framework не может считывать сам синтаксис выражения запроса. Поэтому во время компиляции выражения запросов претворяются в то, что среда CLR понимает: вызовы методов. Эти методы называются стандартными операторами запросов. В качестве разработчика вы можете вызывать их непосредственно с помощью синтаксиса метода, а не с помощью синтаксиса запросов. Дополнительные сведения см. в разделе Синтаксис запросов и синтаксис метода в LINQ. Дополнительные сведения о стандартных операторах запросов см. в обзоре операторов стандартных запросов.

В следующем примере используется Select для возврата всех строк из таблицы Product и отображения имен продуктов.

// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);

DataTable products = ds.Tables["Product"];

IEnumerable<DataRow> query =
    from product in products.AsEnumerable()
    select product;

Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
    Console.WriteLine(p.Field<string>("Name"));
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)

Dim products As DataTable = ds.Tables("Product")

Dim query = From product In products.AsEnumerable() _
            Select product
Console.WriteLine("Product Names:")
For Each p In query
    Console.WriteLine(p.Field(Of String)("Name"))
Next

Синтаксис запросов Method-Based

Другой способ сформулировать запросы LINQ to DataSet заключается в использовании запросов на основе методов. Синтаксис запроса на основе метода — это последовательность прямых вызовов методов оператора LINQ, передавая лямбда-выражения в качестве параметров. Дополнительные сведения см. в лямбда-выражений.

В этом примере используется Select для возврата всех строк из Product и отображения имен продуктов.

// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);

DataTable products = ds.Tables["Product"];

var query = products.AsEnumerable().
    Select(product => new
    {
        ProductName = product.Field<string>("Name"),
        ProductNumber = product.Field<string>("ProductNumber"),
        Price = product.Field<decimal>("ListPrice")
    });

Console.WriteLine("Product Info:");
foreach (var productInfo in query)
{
    Console.WriteLine($"Product name: {productInfo.ProductName} Product number: {productInfo.ProductNumber} List price: ${productInfo.Price} ");
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)

Dim products As DataTable = ds.Tables("Product")

Dim query = products.AsEnumerable() _
    .Select(Function(product As DataRow) New With _
    { _
        .ProductName = product.Field(Of String)("Name"), _
        .ProductNumber = product.Field(Of String)("ProductNumber"), _
        .Price = product.Field(Of Decimal)("ListPrice") _
    })

Console.WriteLine("Product Info:")
For Each product In query
    Console.Write("Product name: " & product.ProductName)
    Console.Write("Product number: " & product.ProductNumber)
    Console.WriteLine("List price: $ " & product.Price)
Next

Создание запросов

Как упоминалось ранее в этом разделе, переменная запроса сохраняет только команды запроса, когда запрос предназначен для возврата последовательности значений. Если запрос не содержит метод, который приведет к немедленному выполнению, фактическое выполнение данного запроса откладывается до тех пор, пока вы не выполните итерацию по переменной запроса в цикле foreach или For Each. Отложенное выполнение позволяет объединить несколько запросов или расширить запрос. Если запрос расширен, он изменяется, чтобы включить новые операции, и в конечном итоге выполнение будет отражать изменения. В следующем примере первый запрос возвращает все продукты. Второй запрос расширяет первый с помощью Where для возврата всех продуктов размера "L":

// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);

DataTable products = ds.Tables["Product"];

IEnumerable<DataRow> productsQuery =
    from product in products.AsEnumerable()
    select product;

IEnumerable<DataRow> largeProducts =
    productsQuery.Where(p => p.Field<string>("Size") == "L");

Console.WriteLine("Products of size 'L':");
foreach (DataRow product in largeProducts)
{
    Console.WriteLine(product.Field<string>("Name"));
}

' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)

Dim products As DataTable = ds.Tables("Product")

Dim productsQuery = From product In products.AsEnumerable() _
                    Select product

Dim largeProducts = _
    productsQuery.Where(Function(p) p.Field(Of String)("Size") = "L")

Console.WriteLine("Products of size 'L':")
For Each product In largeProducts
    Console.WriteLine(product.Field(Of String)("Name"))
Next

После выполнения запроса дополнительные запросы не могут быть созданы, а все последующие запросы будут использовать операторы LINQ в памяти. Выполнение запроса происходит при итерации переменной запроса в операторе foreach или For Each или вызове одного из операторов преобразования LINQ, которые вызывают немедленное выполнение. Эти операторы включают следующие: ToList, ToArray, ToLookupи ToDictionary.

В следующем примере первый запрос возвращает все товары, упорядоченные по прейскурантной цене. Метод ToArray используется для принудительного выполнения немедленного выполнения запросов:

// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);

DataTable products = ds.Tables["Product"];

IEnumerable<DataRow> query =
    from product in products.AsEnumerable()
    orderby product.Field<Decimal>("ListPrice") descending
    select product;

// Force immediate execution of the query.
IEnumerable<DataRow> productsArray = query.ToArray();

Console.WriteLine("Every price from highest to lowest:");
foreach (DataRow prod in productsArray)
{
    Console.WriteLine(prod.Field<Decimal>("ListPrice"));
}
' Fill the DataSet.
Dim ds As New DataSet()
ds.Locale = CultureInfo.InvariantCulture
' See the FillDataSet method in the Loading Data Into a DataSet topic.
FillDataSet(ds)

Dim products As DataTable = ds.Tables("Product")

Dim query = _
        From product In products.AsEnumerable() _
        Order By product.Field(Of Decimal)("ListPrice") Descending _
        Select product

' Force immediate execution of the query.
Dim productsArray = query.ToArray()

Console.WriteLine("Every price From highest to lowest:")
For Each prod In productsArray
    Console.WriteLine(prod.Field(Of Decimal)("ListPrice"))
Next

См. также