asp.net|数据 一、 简介
作为开发人员,当我们在学习新技术时,例子可能是我们最大的敌人。而教程往往设计得易于理解,但是同时,它们常常加固了懒惰,低效性,甚至于危险的编码习惯。再也没有比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来实现相同的任务):
SELECTSalesOrderID, 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参数以进一步缩小结果范围。这样可以防止我们返回数据库的每一个订单。点选"Fill a DataTable"和"Return a DataTable"复选框,然后点击Finish。在添加这个SELECT语句后,你的设计者现在应该有一个外部查询已经添加到这个SalesOrderHeaderTableAdapter,请参考下面的屏幕快照。
四、 在一个ASP.NET页面上使用强类型DataSet
通过创建强类型DataSet,我们可以仅通过编写几行代码就可以实现容易地在一个ASP.NET页面显示这些数据。首先,在你的网站上创建一个ASP.NET页面并且在设计模式中观察它。然后,拖放一个GridView控件到其上,保持其ID为GridView1。打开ASP.NET页面的源代码并且在文件的顶部导入AdventureWorksTableAdapters命名空间(在C#中,该语法为:"using AdventureWorksTableAdapters;")。最后,把下列代码添加到Page_Load事件处理器中:
SalesOrderHeaderTableAdapter salesAdapter =
new SalesOrderHeaderTableAdapter();
//得到发生于2004年7月1日之后的订单
AdventureWorks.SalesOrderHeaderDataTable Orders =
salesAdapter.GetDataBy(new DateTime(2004, 7, 1));
//把订单结果绑定到GridView
this.GridView1.DataSource = Orders;
this.GridView1.DataBind();
这段代码是很简单的。我们创建SalesOrderHeaderTableAdapter的一个实例-我们将使用它来填充DataTable。注意,不是声明一个泛型DataTable,我们声明了一个SalesOrderHeaderDataTable类型的对象。为了填充这个DataTable,我们调用GetDateBy()方法并且传递给它一个DateTime对象。还要注意,甚至这个检索命令也是强类型化的,因为我们必须传递一个DateTime对象,而不仅仅是一个泛型对象。下面的屏幕快照显示了上面示例代码的清晰结果。
除了通过代码把结果绑定到GridView外,你还可以使用一个ObjectDataSource,设置它的TypeName属性为AdventureWorksTableAdapters.SalesOrderHeaderTableAdapter,并且把它的SelectMethod设置为GetData或GetDataBy。
五、 使用强类型DataSet插入、更新和删除数据
在本文中,我们已经看到了怎样使用一个强类型DataSet从一个数据库中选择数据。然而,你还可以使用这些工具来插入、更新和删除基本的数据库数据。
除了不必编写代码来存取数据库外,使用这个强类型化的DataSet的另外一个很大的优点是,在此不存在编译器不能检查的字符串列名潜伏在我们的代码并且我们不必进行任何对象转换。如果我们曾经改变过我们的数据库模式,那么一旦我们更新我们的AdventureWorks.xsd文件,我们将注意到在编译期间的存在于我们的应用程序中的所有的巨大变化。
六、 小结
其实,除了使用强类型DataSet外,还有另外的方法来实现你的应用程序的强类型化。你可以创建定制类-比DataSet更为轻量级并且能够正确地响应于你的数据库。而且,还有一些第三方软件开发者提供工具来自动化这一过程。其中,一个特别的产品是LLBLGen Pro,就是我比较喜欢的工具之一,我还写了有关于它的一本书:《Rapid C# Windows Development: Visual Studio 2005, SQL Server 2005,and LLBLGen Pro》。另外一个流行的工具是CodeSmith。甚至微软也在使用一个与之类似的工具-DLINQ,它仍处于测试阶段,至少在下一年中不会上市。
如果你使用Visual Studio强类型DataSet方法,那么你不需要购买任何另外的软件-这是一个明显的优点。所有这些解决方案都有其各自不同的特征和优点,但是强类型化你的关系数据的主要优点还在于:可靠性,更少的错误和更少的调试时间花费;另外,分析数据库模式变化的影响并实现它们也更为容易。最后,非常希望你已经了解到强类型化的优点。祝你幸运!