在 LINQ to DataSet 中查询

查询是一种从数据源检索数据的表达式。 查询通常用专用查询语言表示,如用于关系数据库的 SQL 和用于 XML 的 XQuery。 因此,开发人员对于他们查询的每种类型的数据源或数据格式,都不得不学习一种新的查询语言。 语言集成查询 (LINQ) 为跨各种数据源和格式处理数据提供了一种更简单的、一致的模型。 在 LINQ 查询中,您始终可以使用编程对象。

LINQ 查询操作包含三个操作:获得一个或多个数据源、创建查询并执行查询。

可以通过 LINQ 查询实现 IEnumerable<T> 泛型接口的数据源。 对 AsEnumerable 调用 DataTable 将返回实现泛型 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

基于方法的查询语法

表述 LINQ to DataSet 查询的另一种方法是使用基于方法的查询。 基于方法的查询语法是一系列针对 LINQ 运算符方法的直接方法调用,同时将 lambda 表达式作为参数传递。 有关详细信息,请参阅 Lambda 表达式

此示例使用 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: {0} Product number: {1} List price: ${2} ",
        productInfo.ProductName, productInfo.ProductNumber, 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

请参阅