日期:2010-10-03  浏览次数:20399 次

  一、 简介

  作为开发人员,当我们在学习新技术时,例子可能是我们最大的敌人。而教程往往设计得易于理解,但是同时,它们常常加固了懒惰,低效性,甚至于危险的编码习惯。再也没有比ADO.NET示例更能说明问题的了。在本文中,我们将准备分析一下强类型对象对于你的数据库开发的意义以及为什么在没有例子的情况下你应该在应用程序中尽量使用强类型对象。

  具体地说,我们将分析怎样在Visual Studio 2005中创建和使用强类型DataSet。正如本文所探讨的,相对于其它可选的弱类型化的数据存取技术,强类型DataSet提供了很多优点;并且,借助于Visual Studio 2005,创建和使用强类型DataSet比以往更为容易。

  二、 强类型对象基础及优点

  为了理解强类型化的含义,不妨让我们先考虑一下约会的例子。如果你是一个单身汉,那么,你盼望与什么类型的人约会呢?你可能已经有了自己具体的标准,如富裕且吸引人或可能是居住条件优越而性感。无论你的条件如何,当你决定想与谁在一起呆更长的时间时,你都难免有一套自己的约会标准。如果你很明智,可以列出一个经过事先深思熟虑的列表,这样可以帮助你节约不必要的感情付出。把一项"非酗酒"的条件加入到你的约会标准中将会节约你大量的时间,并且允许你把你的时间和精力用于与更好的候选者约会。

  你可能疑惑,这怎么能与编程进行比较呢?请听我的解释。ADO.NET数据存取对象的设计是为了实现最大的灵活性。除非你遇到相当大的麻烦,否则,当你从数据库读取数据时,你都会使用大量普通的未经类型化的对象-当然,.NET框架完全允许这样做。而使用我们的约会类比法,总是把你的关系数据当作泛型对象则有点象承认"我只与满足我条件的人约会"。难道你不能稍微放宽一些条件吗?作为你的朋友,我必须建议你"先确定一些标准,再精简一下你的列表!"也许更好些。

  正如忽视筛选你要约会的人能够导致未来的关系问题,与你的对象保持"松耦合"能够给你的代码带来错误。另外,因为如果你让任何旧对象"出入"你的子程序的话,那么,直到你的应用程序在运行时刻执行时,你可能才会知道存在问题。在我们的日期约会类比中,在运行时刻捕获错误很类似于你与你的约会者在一家时髦的意大利餐馆进行一场痛苦而尴尬的讨论。是的,你发现了这个问题;但是,如果你已经事先计划好的话,那么你的结果就不会是"一群用餐者盯着你,而你满身是意大利烤碎肉卷"。如果你简单地把一些更紧密的标准应用于你的代码中,那么在你的应用程序开始运行前(在编译时刻)你就能够捕获错误。例如,请考虑下面的示例代码:

string FirstName = myrow.("FirstName").ToString();

  上面的DataRow就是非类型化的;结果,你必须以一个串形式作为你要查询的列名来存取这个值(或者,使用这个列集合中的列的索引值)。很可能,这个列真正存在。一个DataRow列的数据类型是对象;我们假定FirstName列的基本数据类型是字符串,但是,我们必须显式地把它转化成一个字符串以便使用它。如果列名发生变化(例如,你把它改为PersonFirstName),那么编译器是不能通知你的。千万不要这样!因此,如果你的代码看起来更象如下形式,那么你的生活就会更容易些而你的代码将更为可靠:

string FirstName = PersonRow.FirstName;


  在第二个例子中,我们拥有一个强类型行,并且我们知道FirstName属性是字符串类型。在此,不会出现杂乱的列名,而且也不存在杂乱的对象转换问题。编译器为我们作类型检查,并且我们可以继续进行其它任务而不必担心是否我们已经正确输入了列名。

  对于所有其它列也是如此;总之,当你能够使用一个更为具体的类型时,你永远不应该使用一个泛型对象。但是,请等一下。该强类型对象出自何处?我想我能够告诉你这些对象是为你自动创建的。然而,正如要建立良好的关系需要时间和精力一样,强类型化你的对象也需要付出其它努力。好的方面在于,这里所花费的额外时间是值得的,而且节省了将来更多的花在调试上的时间。

  存在若干种可以实现强类型化的方法,在本文余下的部分中,我们将讨论怎样在Visual Studio 2005中创建强类型DataSet;当然,还将分析一下这样做的优点和缺点。

  三、 在VS 2005中创建强类型DataSet

  其实,强类型DataSet是一些提前定义了它们自己的列与表的泛型DataSet,这样编译器已经知道它们将会包含什么内容。不是把你的数据包装为一个"露指手套",一个强类型DataSet恰似一个"手套"。每一个Visual Studio的后续版本会使得强类型化一个DataSet的过程更为容易。在这个示例中,我们将使用来自于SQL Server 2005中的AdventureWorks数据库。这只要简单地执行如下步骤:

  1. 打开Visual Studio,然后创建一个新的ASP.NET网站。

  2. 在Solution Explorer中,占击以添加一个新项并且选择DataSet,并命名为AdventureWorks.xsd。Visual Studio推荐把这个DataSet文件放到App_Code文件夹下。

  3. 这个AdventureWorks.xsd将在设计模式下打开,并且激活"TableAdapter Configuration"向导。现在,仅仅点击一下"Cancel"即可。

  4. 定位到Server Explorer工具箱,导航到你的SQL Server 2005数据库和AdventureWorks数据库。(如果你还没有安装AdventureWorks数据库的话,你可以从微软的SQL Server 2005 Samples and Sample Databases下载页面下载它,还有另外的SQL Server 2005示例。)

  5. 把SalesOrderHeader和SalesOrderDetail表拖动到你的DataSet设计器窗口。现在,这个窗口应该类似于下面的屏幕快照。注意,对于我们加入的每个表,Visual Studio都创建一个强类型DataTable(该名称是基于原始的表)和一个TableAdapter。这个DataTable为我们定义了每一个列。这个表适配器是我们用来填充这个表的对象。缺省情况下,我们有一个Fill()方法,由它找到表中的每一行。

  这个强类型DataSet将返回在这两个表中的所有记录。既然AdventureWorks数据库包含大量的订单信息,那么我们为什么不创建一个更为具体些的查询呢?我们可以把方法添加到我们的TableAdapter对象来检索一个更为具体的表的记录子集。首先,右击SalesOrderHeaderTableAdapter,并且选择"Add|Query"。选择"Use SQL statements"并且点击Next按钮。然后,选择"SELECT which returns rows"并且点击Next按钮。最后,在窗口中输入下列查询(或使用Query Builder来实现相同的任务):

SELECT
SalesOrderID, RevisionNumber, OrderDate, DueDate, ShipDate,
Status, OnlineOrderFlag, SalesOrderNumber, PurchaseOrderNumber,
AccountNumber, CustomerID, ContactID, SalesPersonID, TerritoryID,
BillToAddressID, ShipToAddressID, ShipMethodID, CreditCardID,
CreditCardApprovalCode, CurrencyRateID, SubTotal, TaxAmt, Freight,
TotalDue, Comment, rowguid, ModifiedDate
FROM Sales.SalesOrderHeader
WHERE (OrderDate > @OrderDate)

  这个SQL查询是一个简单的SELECT查询,它有一个@OrderDate参数以进一步缩小结果范围。这样可以防止我们返回数据库的每一个订单。点