LINQ to DataSet 中的查询

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

一个 LINQ 查询操作包含三个操作:获取数据源、创建查询和执行查询。

实现 IEnumerable<T> 泛型接口的数据源可以通过 LINQ 进行查询。 对 DataTable 调用 AsEnumerable 将返回实现泛型 IEnumerable<T> 接口的对象,作为 LINQ to DataSet 查询的数据源。

在查询中,指定您要从数据源中检索的准确信息。 查询也可以指定返回信息之前信息的排序、分组和表现方式。 在 LINQ 中,查询存储在变量中。 如果查询旨在返回一系列值,则查询变量本身也必须为可枚举类型。 此查询变量不执行任何操作,也不返回任何数据;它只存储查询信息。 创建查询后必须执行该查询以检索任何数据。

在返回一系列值的查询中,查询变量本身从不保存查询结果,它只存储查询命令。 查询的执行将推迟到在 foreach 或 For Each 循环中循环访问查询变量之后进行。 这称为“延迟执行”;也就是说,查询将会在构造之后的某个时间执行。 这意味着您可以根据需要频繁地执行查询。 例如,当您的数据库由其他应用程序不断更新时,此功能将会很有用。 在您的应用程序中,您可以创建查询以检索最新信息并重复执行查询,每次返回更新的信息。

与返回一系列值的延迟查询相反,返回单一实例值的查询将立即执行。 CountMaxAverageFirst 是一些单一实例查询的示例。 因为需要查询结果来计算单一实例结果,因此这些查询将会立即执行。 例如,若要计算查询结果的平均值,则必须执行查询,以便求平均值函数具有要使用的输入数据。 您也可以对查询使用 ToList<TSource>ToTSource> 方法以强制立即执行不生成单一实例值的查询。 当想要缓存查询结果时,这些强制立即执行的技术可能会很有用。 有关延迟和立即执行查询的更多信息,请参见 Getting Started with LINQ

查询

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

查询表达式语法

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

查询表达式语法是 C# 3.0 和 Visual Basic 2008 中的新功能。 不过,.NET Framework 公共语言运行库 (CLR) 无法读取查询表达式语法本身。 因此,在编译时,查询表达式将转换为 CLR 能理解的形式,即方法调用。 这些方法称为“标准查询运算符”。 作为开发人员,您可以选择使用方法语法而不使用查询语法直接调用这些方法。 有关更多信息,请参见LINQ 查询语法与方法语法 (C#)。 有关如何使用标准查询运算符的更多信息,请参见 LINQ 常规编程指南

下面的示例使用 Select 返回 Product 表中的所有行并显示产品名称。

' 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
// 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"));
}

基于方法的查询语法

表述 LINQ to DataSet 查询的另一种方法是使用基于方法的查询。 基于方法的查询语法是对 LINQ 运算符方法的一系列直接方法调用,将 Lambda 表达式作为参数进行传递。 有关更多信息,请参见 Lambda 表达式(C# 编程指南)

此示例使用 Select 返回 Product 中的所有行并显示产品名称。

' 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
// 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);
}

编写查询

如本主题前面所述,当查询旨在返回一系列值时,查询变量本身只存储查询命令。 如果查询不包含可使查询立即执行的方法,则查询的实际执行将会推迟,直到在 foreach 或 For Each 循环中循环访问查询变量。 延迟执行可使多个查询组合在一起或使查询得到扩展。 扩展查询时,将修改查询以包括新操作,最终执行将反映这些更改。 在下面的示例中,第一个查询返回所有产品。 第二个查询通过使用 Where 扩展第一个查询,以返回大小为“L”的所有产品:

        ' 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

            // 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"));
            }


执行一个查询后,不会再编写其他查询,并且所有后续查询都将使用驻留在内存中的 LINQ 运算符。 当在 foreach 或 For Each 语句中循环访问查询变量或通过调用可导致立即执行的 LINQ 转换运算符之一时,查询将会开始执行。 这些运算符包括:ToList<TSource>ToTSource>ToLookupToDictionary

在下面的示例中,第一个查询返回按定价排序的所有产品。 ToTSource> 方法用于强制立即执行查询:

' 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
// 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"));
}

请参见

概念

查询数据集 (LINQ to DataSet)

其他资源

编程指南 (LINQ to DataSet)

C# 中的 LINQ 入门

Visual Basic 中的 LINQ 入门