痛而后能善
无惧于闯
Make a greate impact

[翻译]Pro C# 2008 and the .NET 3.5 Platform, Fourth Edition 第二十四章 LINQ API编程(二)

本章翻译目的为学习之用,英文版权属原作者所有,中文版权根据turingbook的贴子归图灵,如有侵权,请告知删除,禁止用于商业用途!在此特别鸣谢图灵的傅老师(本章翻译的贴出征得她的同意)和杨福川(为大家介绍了这本好书)。本人翻译水平有限,错误之处难免望大家批评指正!本文仅摘出一部分。

 

 

获取与LINQ兼容的DataTable

为了说明DataSet扩展的使用,假设你已经创建了一个LinqOverDataSet的C#控制台程序。注意,在你创建.NET 3.5项目的时候,就会自动添加System.Core.dll和System.Data.DataSetExtensions.dll的引用;但是,对于这个例子,添加额外的引用,这些引用在第23章中创建的AutoLotDAL.dll程序集中,并且用以下的逻辑更新初始代码文件:

using System.Data;

using AutoLotDisconnectedLayer;

namespace LinqOverDataSet

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("***** LINQ over DataSet *****"n");

            // 获取包含the AutoLot 数据库中当前存货清单 DataTable 的数据.

            InventoryDALDisLayer dal = new InventoryDALDisLayer(

            @"Data Source=(local)"SQLEXPRESS;Initial Catalog=AutoLot;" +

            "Integrated Security=True");

            DataTable data = dal.GetAllInventory();

            // 像如下调用方法

            Console.ReadLine();

        }

    }

}

       当你希望转换ADO.NET DataTable成LINQ兼容的对象的时候,你只需要简单的调用由DataTableExtensions类定义的AsEnumerable()扩展方法。它会返回一个EnumerableRowCollection对象,该对象包含了DataRows集合。运用EnumerableRowCollection类,接下来你就能如期地操作每一行。举一个简单的例子:

    static void PrintAllCarIDs(DataTable data)

    {

        // 获取DataTable的可枚举版本.

        EnumerableRowCollection enumData = data.AsEnumerable();

        // 打印 the car ID 的值.

        foreach (DataRow r in enumData)

            Console.WriteLine("Car ID = {0}", r["CarID"]);

    }

 

因为EnumerableRowCollection实现了IEnumerable<T>接口,它被允许用以下的代码段捕获返回值:

    // 存储IEnumerable<T>类型的返回值

    IEnumerable<DataRow> enumData = data.AsEnumerable();

    // 隐藏存储的返回值.

    var enumData = data.AsEnumerable();

在这里,实际上我们没有运用LINQ查询;然而,关键是enumData对象现在能够成为LINQ查询表达式的对象。我们也注意到EnumerableRowCollection确实包含了DataRow对象集合,当我们使用类索引器而非每一个子类打印出CarID列的值。

       在大多数情况下,你不需要声明一个EnumerableRowCollection类型变量来存储AsEnumerable()的返回值。甚至,可以在查询表达式中调用该方法。有一个更有趣的方法,它获取CarID的映射,在CarID大于5之处返回所有DataTable的实例。

    static void ApplyLinqQuery(DataTable data)

    {

        // Project a new result set containing

        // the ID/color for rows with a CarID > 5

        var cars = from car in data.AsEnumerable()

                   where

                   (int)car["CarID"] > 5

                   select new

                   {

                       ID = (int)car["CarID"],

                       Color = (string)car["Color"]

                   };

        Console.WriteLine("Cars with ID greater than 5:");

        foreach (var item in cars)

        {

            Console.WriteLine("-> CarID = {0} is {1}", item.ID, item.Color);

        }

    }

 

DataRowExtensions.Field<T>()扩展方法的作用

当前LINQ查询表达式的不友好的一个方面是,我们在使用许多类型转换操作和运用DataRow索引器来获得结果集,如果我们尝试转换不兼容的数据类型,这就会产生运行时异常。为了植入一些强类型到我们的查询当中,我们可以使用DataRow类型的Field<T>()扩展方法。这样做是为了提高查询的类型安全性,同时在编译的时候检查数据类型的兼容性。

考虑以下的更新:

    var cars = from car in data.AsEnumerable()

               where

               car.Field<int>("CarID") > 5

               select new

               {

                   ID = car.Field<int>("CarID"),

                   Color = car.Field<string>("Color")

               };

注意这种情况下我们可以调用Field<T>()和定义一个类型参数来表示底层列的数据类型。用列名作为参数并传递给该方法。进行额外的编译检查时,在考虑EnumerableRowCollection作用的时候,最实用的就是使用Field<T>(),而非DataRow索引器。

       除此以外我们调用AsEnumerable()方法,大体上LINQ查询格式和你在第十四章看到的完全相同。基于这一点,我不厌其烦的在这里重复很多LINQ操作符细节。如果你希望看更多的例子,在.NET Framework 3.5开发文档中可以搜索到关于“LINQ to DataSet示例“的主题。

从LINQ查询合成新DataTable

在基于LINQ查询结果集并且不使用映射,简单地把数据移植到新DataTable是可行的。当你有一可用于表示为IEnumerable<T>底层类型的结果集的时候,你可以调用结果集中的CopyToDataTable<T>()扩展方法。比如:

    static void BuildDataTableFromQuery(DataTable data)

    {

        var cars = from car in data.AsEnumerable()

                   where

                   car.Field<int>("CarID") > 5

                   select car;

        // 用这一结果集创建一个新的DataTable.

        DataTable newTable = cars.CopyToDataTable();

        // 打印 DataTable.

        for (int curRow = 0; curRow < newTable.Rows.Count; curRow++)

        {

            for (int curCol = 0; curCol < newTable.Columns.Count; curCol++)

            {

                Console.Write(newTable.Rows[curRow][curCol].ToString().Trim() + ""t");

            }

            Console.WriteLine();

        }

    }

 

注意:通过AsDataView<T>()方法把LINQ查询转换为DataView类型是可行的。

 

这种方法在用LINQ查询的结果作为数据绑定源的时候非常有效。例如,WinForms的DataGridView(ASP.NET下是GridView)都支持一个叫DataSource的属性。你可以把LINQ结果集绑定到grid控件去,如下所示:

// 假设 myDataGrid 是基于用户控件的grid对象.

myDataGrid.DataSource = (from car in data.AsEnumerable()

where

car.Field<int>("CarID") > 5

select car).CopyToDataTable();

既然你已经了解LINQ to DataSet的作用,让我们把注意转向LINQ to SQL。

源代码:LinqOverDataSet示例在第二十四章的子目录下。

posted on 2008-09-03 19:19  greater  阅读(2114)  评论(0编辑  收藏  举报