LINQ to DataSet 中的查询

查询是从数据源检索数据的表达式。 查询通常以专用查询语言表示,例如 SQL(用于关系数据库)和 XQuery for XML。 因此,开发人员必须了解其查询的每种类型的数据源或数据格式的新查询语言。 Language-Integrated 查询(LINQ)提供了一个更简单、一致的模型,用于处理各种数据源和格式的数据。 在 LINQ 查询中,始终使用编程对象。

LINQ 查询作由三个作组成:获取数据源或源、创建查询和执行查询。

可以通过 LINQ 查询实现泛型接口的 IEnumerable<T> 数据源。 调用某个AsEnumerableDataTable对象将返回一个实现泛型IEnumerable<T>接口的对象,该接口充当 LINQ to DataSet 查询的数据源。

在查询中,请准确指定要从数据源检索的信息。 查询还可以指定在返回信息之前应如何对信息进行排序、分组和调整。 在 LINQ 中,查询存储在变量中。 如果查询设计为返回值序列,则查询变量本身必须是可枚举的类型。 此查询变量不执行任何作,不返回任何数据;它只存储查询信息。 创建查询后,必须执行该查询以检索任何数据。

在返回值序列的查询中,查询变量本身永远不会保存查询结果,并且只存储查询命令。 查询的执行会被推迟,直到查询变量在foreachFor Each循环中被迭代。 这称为 延迟执行;也就是说,查询执行在构造查询后一段时间发生。 这意味着可以尽可能频繁地执行查询。 例如,当你有一个数据库正在由其他应用程序更新时,这非常有用。 在应用程序中,可以创建一个查询来检索最新信息并重复执行查询,每次返回更新的信息。

与返回值序列的延迟查询相比,返回单个值的查询会立即执行。 单一实例查询的一些示例包括CountMaxAverageFirst。 因为需要查询结果来计算单一实例结果,因此这些查询将会立即执行。 例如,若要查找查询结果的平均值,必须执行查询,以便平均函数具有要使用的输入数据。 还可以对不生成单一结果值的查询使用 ToListToArray 方法来强制其立即执行。 如果要缓存查询结果,这些强制立即执行的技术非常有用。

查询

LINQ to DataSet 查询可以采用两种不同的语法来表述:查询表达式语法和基于方法的查询语法。

查询表达式语法

查询表达式是声明性查询语法。 此语法使开发人员能够以类似于 SQL 的格式以 C# 或 Visual Basic 编写查询。 通过使用查询表达式语法,可以使用最少的代码对数据源执行复杂的筛选、排序和分组作。 有关详细信息,请参阅 LINQ 查询表达式基本查询作(Visual Basic)。

.NET Framework 公共语言运行时 (CLR) 无法读取查询表达式语法本身。 因此,在编译时,查询表达式将转换为 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 运算符方法的直接方法调用序列,将 lambda 表达式作为参数传递。 有关详细信息,请参阅 Lambda 表达式

此示例使用 SelectProduct 返回所有行,并显示产品名称。

// 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

编写查询

如本主题前面所述,查询变量本身仅在查询设计为返回值序列时存储查询命令。 如果查询不包含会导致立即执行的方法,则查询的实际执行将被延迟,直到在foreachFor 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 运算符。 当您在foreachFor Each语句中迭代查询变量,或者通过调用导致立即执行的 LINQ 转换运算符之一时,将发生查询执行。 这些运算符包括: ToListToArrayToLookupToDictionary

在以下示例中,第一个查询返回按标价订购的所有产品。 该方法 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

另请参阅