LINQ to DataSet 中的查询

更新:November 2007

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

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

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

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

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

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

查询

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

查询表达式语法

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

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

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

' 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 入门