使用强类型数据集进行有效编码——转载

曾经有人告诉我优秀的开发人员的特点是希望能够有效地利用时间。开发人员不断追求更容易更快速的编码方式,以及减少错误数量的方法。使用 ADO.NET 中的强类型数据集对象可以帮助您做到这一点。

本月我将从正反两方面来讨论使用强类型数据集对象开发基于 Microsoft .NET Framework 的应用程序。我将从什么是强类型数据集及其如何扩展数据集、数据表和 DataRow 类开始谈起。在这一部分中,我将提到一个示例应用程序,它包括使用强类型数据集在 SQL Server Northwind 数据库的 Orders 和 Order Details 表上执行插入、更新和删除的完整代码。。该示例多层应用程序(可以从本文前面的链接中下载)在若干层中使用类型化数据集,包括用作业务逻辑层的类库、Web 服务和 ASP.NET Web 应用程序。最后,我将以使用强类型数据集时可以利用的一些提示和技巧来结束本文。

类型化的值

记得 IntelliSense 之前的生活么?它并不像 Internet 引入时那样具有翻天覆地的变化,但是对于我这样的开发人员(一直在寻找更快的编码方式以及可以更容易地记住所有属性、方法和对象的事件名称的方式)来说,IntelliSense 已经很好了。一个还没有从 IntelliSense 获益的领域是传统的 ADO 记录集。例如,在传统的 ADO 2.x 编程中,您必须使用类似下面的 Visual Basic 6.0 代码来引用记录集中某个列的值:

oRecordset.Fields("CompanyName").Value

当然,为了减少代码,您可以删除 Fields 集合和 Value 属性,因为它们是其各自对象的默认属性。但是,如果列名拼写有误,那么编译时您也不会获得出错通知。还有,如果连列名都忘记了,那么您就必须返回去查看存储过程、SQL 语句、XML 文件或其他数据源。

在传统的 ADO 中引用列的另一种方式是通过其序号位置(使用索引或自定义枚举器)。整数是最简单的,但是这里再次强调,您可能很容易忘记该列在哪个序号位置,甚至忘记列是从位置 0 开始的,从而导致索引偏移一位。使用序号位置也使得可读性成为一个问题。当您在一个星期、一个月或一年后回头查看代码时,您可能就不记得第 2 列代表什么了。

创建自定义枚举器有助于提高可读性,这也是我在处理传统 ADO 中的这一问题时更喜欢的方式。但是,如果有人改变了列从存储过程返回到 ADO 的顺序,那么列仍然会失去同步。所有这些都是开发人员在传统 ADO 编程中遇到的常见问题,使用 ADO.NET 中的非类型化数据集对象时也会遇到类似问题。这些只是使用强类型数据集所解决的一小部分问题。

例如,类型化数据集包含非类型化数据集所没有的附加方法和属性。请看以下代码段,它使用类型化和非类型化数据集来引用 ADO.NET 中的列:

//-- Untyped DataSet
string sCoName =
oDs.Tables["Customers"].Rows[0]["CompanyName"].ToString();
//-- Strongly typed DataSet
string sCoName = oDs.Customers[0].CompanyName;

类型化数据集代码更短,不需要通过字符串或序号位置访问表名或者列名,也不需要 Row 属性。您可以使用 IntelliSense 来获得类型化数据集可以使用的表名列表及其表可以使用的列名列表,因此很容易编写代码。注意,在非类型化数据集代码中,必须使用 ToString 方法来检索列中所包含值的字符串表示。在类型化数据集中,根据各个列的数据类型将所有列都定义为属性。例如,CompanyName 属性定义为字符串类型,这样就不需要 ToString 方法。由于类型化数据集中包含架构信息,所以更容易绑定到控件。将类型化数据集绑定到 ASP.NET DataGrid 时,属性菜单会读取所选类型化数据集的架构,并识别类型化数据集所公开的数据表和数据列。Properties 窗口会用所选数据集的数据表对象的名称填充 DataMember 列表。同样,可用字段列表会加载到 DataKeyField 属性中(如图 1 所示)。此功能消除了编写这种代码的必要,减少了出现任何错误拼写的可能性,甚至使得不需要记住架构中表和列的名称(注意,如果使用 ReadXmlSchema 方法将架构读取到数据集中,使用非类型化数据集也可以获得同一功能)。(参看提要栏“创建一个类型化数据集”。)

图 1 数据绑定属性

强制转换调用

强类型数据集对象的列定义为特殊的数据类型。例如,Northwind 数据库的 Orders 表中 OrderDate 列定义为日期时间类型。从 Northwind Orders 表中创建强类型数据集将具有日期时间的数据类型,分别对应于数据库中各自的副本。列的这种显式类型化消除了显式强制转换的必要,以从数据集中获得值或将值写入数据集,正如前面的代码示例所示,其中,我从 Customers 数据表中检索 CompanyName。此功能减少了从数据集中获得值或将值写入数据集所需要编写的代码的数量。因而,强类型数据集为开发人员提供了更快的开发和更少的运行时错误,因为像列和字段名拼写不正确这样的错误在编译时很容易被发现。

有几种方式可以引用 DataColumn 的值(使用各种可用的重载方法)。其中有些方法执行的速度比其他的方法快,而且还有些方法可读性更强,更易于维护。当引用非类型化数据集中的列时,维护和性能方面会有所不同。强类型数据集在速度和易于维护性方面优于非类型化数据集。访问类型化数据集的速度可与访问非类型化数据集的更快的技术相媲美(因为类型化数据集只是非类型化数据集上面的一层),并且类型化数据集的可读性是最好的:oDs.Orders[0].OrderDate。以下非类型化数据集技术在方便性和性能上有各种组合。首先,可以使用 DataColumn 实例来访问列值:

oDs.Tables["Orders"].Rows[0][DataColumn]

这可能是最不方便的,因为您需要首先获得 DataColumn 实例。但是其执行速度最快。如果要从多行中检索值,这就是一个很好的解决方案,因为可以获得一次 DataColumn 实例,然后不断地加以使用。也可以使用其序号位置来访问列,如下面的代码行所示:

oDs.Tables["Orders"].Rows[0][Ordinal]

这可能使您很难确定在引用哪一列,但是其执行速度相当快。第三种选择是使用字符串并根据名称来引用列:

oDs.Tables["Orders"].Rows[0][StringName]

这比序号位置的可读性更强,并且更易于维护,但是其执行速度最慢,因为它必须按照名称来搜索列,而不是像通过序号位置选择所做的那样仅仅在数组中进行索引就可以了。

派生类

它使用 XML Schema Definition (XSD) 文件以及类文件来创建强类型数据集。XSD 文件存储为强类型数据集定义架构的 XML。图 2 显示了一个类型化数据集的关系图视图,它表示 Orders 数据表、OrderDetails 数据表以及这两个表之间的关系。该数据集还描述了这两个表的主键。定义类型化数据集的架构存储在 XSD 文件中。图 2 中显示的视图只是定义强类型数据集的 XML 架构的视觉表示。还有用于存储设计器布局信息的 XML 架构扩展 (Schema Extended, XSX) 文件,它用于描述数据集的视觉表示,如图 2 所示。(此强类型数据集用在示例应用程序中,该示例应用程序可以从 MSDN Magazine Web 站点下载。)

图 2 Orders 数据集

强类型数据集实际上是从 System.Data.DataSet 类中继承的类,并且添加了一些自己的额外功能。该类文件是从 XSD 文件中生成的。右键单击 XSD 的设计视图并选择 Generate DataSet(另外,也可以选择使用 xsd.exe 命令行工具),可以重新生成该类文件。该类文件实际上包含一系列类,这些类继承并扩展了 DataSet、DataTable、DataRow 和 EventArgs 类。由于这种继承性,开发人员使用强类型数据集不会丢失任何功能。例如,即使您可以通过具有与表相同的名称的属性来引用数据表,您仍然可以通过 Tables 集合来引用该表。下面两行对同一数据表对象进行求值:

oDs.Tables["Orders"]
oDs.Orders

强类型数据集类文件包含一个从基数据集继承的类。它还包含数据集中每个数据表的一个类。例如,如果一个强类型数据集中同时有 Orders 和 OrderDetails 两个数据表中,则将有名为 OrdersDataTable 和 OrderDetailsDataTable 的类,它们都是从 DataTable 对象继承的。同样,还有名为 OrdersRow 和 OrderDetailsRow 的类,它们是从DataRow 对象继承的。因为这种继承性,这些类也公开基类所公开的全部标准功能。

强类型数据集还提供了一些附加方法来扩展 DataSet 基类。例如,基于 Northwind 数据库的 Orders 表的类型化数据集会公开 FindByOrderID 方法,它使用一个整数参数来定位带有相应 OrderID 值的 DataRow。因为基类的所有方法和属性都是可用的,所以仍然可以使用标准的 Find 方法,但是扩展属性和方法可以使编写代码对开发人员更容易一些。假定创建了一个如图 2 所示的强类型数据集实例,扩展属性和方法如图 3 所示。

企业应用程序中的类型化数据集

在多层应用程序中使用强类型数据集时,通常要求在所有(至少大部分)的层中强类型数据集都是可用的。通常,在最低层中存储强类型数据集对象及其文件是个不错的主意。这样,引用该层的任何项目和程序集都可以引用该强类型数据集。例如,让我们再次引用该示例应用程序,该应用程序的类库项目(业务逻辑层)中存在一个强类型数据集。Web 服务项目含有对该类库项目的引用,因此它也可以引用该类库项目中所包含的强类型数据集。

我将指出在多层解决方案中使用强类型数据集的位置,并将它们与使用非类型化数据集的编写方式进行比较。首先,看一看图 4,其中显示的代码块将新的 OrderDetailsRow 添加到一个强类型数据集中。此代码块是示例应用程序中 WebForm1.aspx 的 grdOrderDetail_OnItemCommand 事件的示例。我突出显示了使用强类型数据集的扩展方法和属性的相关代码。

又如,以下代码定位类型化数据集中的 OrderDetailsRow。该代码在 WebForm1.aspx 文件的 grdOrderDetail_OnUpdateCommand 事件中:

OrdersDataSet.OrderDetailsRow oRow;
oRow = oDs.OrderDetails.FindByOrderIDProductID(
nOrderID_OrderDetail, nProductID_Original);

此示例代码可以使用非类型化数据集进行编写,如下所示:

DataRow oRow;
oRow = oDs.Tables["OrderDetails"].Rows.Find(
new object[]{nOrderID_OrderDetail, nProductID_Original});

为了演示使用强类型数据集和非类型化数据集之间的其他差别,让我们再看几个示例,它们没有包含在附带的示例应用程序中。例如,如果要检查一个列是否包含空值,并且将其设置为空(如果没有这样设置),则可以使用如下带有强类型数据集的代码:

if(!oDs.Orders[0].IsOrderDateNull())
{
oDs.Orders[0].SetOrderDateNull();}

同样的任务可以用非类型化数据集实现,如以下代码所示:

if(!oDs.Tables["Orders"].Rows[0].IsNull("OrderDate"))
{
oDs.Tables["Orders"].Rows[0]["OrderDate"] = Convert.DBNull;
}

虽然这两个代码块都能完成工作,但是使用强类型数据集的代码更容易编写和阅读。

作为另一个说明使用类型化和非类型化数据集编写代码二者之间差别的示例,我将展示如何获得父表中某一行的所有子行。首先,假定有一个强类型数据集(如前面图 2 中所示)来代表 Orders 和 OrderDetails DataTable 对象。再假定它们彼此关联。如果想要依次通过所有的定单及其所有相关的详细定单数据,可以使用如下代码块:

foreach(OrdersDataSet.OrdersRow oOrderRow in oDs.Orders)
{
Debug.WriteLine("OrderID = " + oOrderRow.OrderID);
foreach(OrdersDataSet.OrderDetailsRow oOrderDetailRow in
oOrderRow.GetOrderDetailsRows())
{
Debug.WriteLine(" — " + oOrderDetailRow.ProductName);
}
}

此代码块依次通过所有的定单,并显示 OrdersRow 的 OrderID 值,然后依次通过定单的 OrderDetailsRow 对象,并显示它们的 ProductName 值。可以通过如下代码块使用非类型化数据集来编写相同的代码:

foreach(DataRow oOrderRow in oDs.Tables["Orders"].Rows)
{
Debug.WriteLine("OrderID = " + oOrderRow["OrderID"].ToString());
foreach(DataRow oOrderDetailRow in
oOrderRow.GetChildRows("Orders2OrderDetails"))
{
Debug.WriteLine(" — " + oOrderDetailRow["ProductName"]);
}
}

此代码块举例说明了这样的事实,使用非类型化数据集编写的代码没有使用强类型数据集编写的代码优雅。

重要花絮

使用类型化数据集时请记住,如果基础数据库表中对应的架构发生改变,则需要同步类型化数据集中的架构。这并不要紧,因为使用非类型化数据集时,如果基础架构发生改变,您仍然可能必须更改一些客户端代码。然而,在这种情况下使用强类型数据集有一个非常大的好处,即编译器可以在用户代码中标记出大部分的必要改动,而使用非类型化数据集在运行时引发异常之前不可能发现错误。在任何情况下,类型化数据集必须与架构保持同步,这一点是值得注意的。

我发现在创建强类型数据集时为其选择名称始终是一个不错的主意。如果在创建之后更改名称,则可能需要重新生成强类型数据集的类文件,因为类和方法不会更新它们的名字以反映新的名称。而且对类型化数据集来说,手动修改生成的类文件通常不是一个好主意。该代码是自动生成的,用于反映 XSD 中定义的架构。而且,如果重新生成类型化数据集的类文件,则您以前可能作的任何手动修改都会丢失,因为该文件将被重写。

规则总是有例外的,修改类型化数据集的类文件或 XSD 的 XML 的一个例外是,当我需要类型化数据集包含一个属性时,我不能通过 XSD 设计器进行设置。例如,在示例应用程序中我设置了两个这样的属性:AutoIncrementStep 和 AutoIncrementSeed。我想让它们从 -1 开始,并且以 -1 为单位递增。设计器中没有界面来设置这些属性,不过我可以查看它们。我在以下代码的第二行中改变 XSD 的 XML 以便包含这些属性:

<xs:element name="OrderID" msdata:ReadOnly="true"
msdata:AutoIncrement="true" msdata:AutoIncrementSeed="-1"
msdata:AutoIncrementStep="-1" type="xs:int" />

通过将此代码添加到 XSD 的 XML中,然后重新生成类文件,强类型数据集就能够对这些自动递增功能进行响应。

使用强类型数据集和 Web 服务还有一些需要记住的重要事情。例如,使用数据集的 Web 服务不能在自动生成的 WSDL 中公开该数据集,除非它的一个 WebMethod 签名以某种方式对其进行引用。

尾声

强类型数据集对象实际上是自编文档 (self documenting) 的,因为它们十分易读。由于它们所代表的表名和列的名称是类型化数据集类的属性,所以使用类型化数据集来编写代码更直观、更易于维护。通过使开发时间更快速、更容易,输入错误更少,代码可维护性更强,强类型数据集极大地帮助了开发人员更高效地编写更有效的代码。

原文发布时间为:2010-03-19

本文来自合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

时间: 2024-10-26 05:47:35

使用强类型数据集进行有效编码——转载的相关文章

求一个通过强类型数据集读取指定格式excel文件,并且显示到reportviewer中的范例

问题描述 不知道说明白没有,不是专业的程序员,只是偶尔帮朋友写段小代码目的就是读取本机的某个EXCEL文件,然后通过reportviewer显示出来和打印EXCEL文件的格式是已知的,例如一共2列(如果能有判断excel文件是否是所需格式的更佳)读取出来然后用reportviewer显示(主要是为了最后多页打印reportviewer比较容易设置--)网络上搜到的介绍,reportviewer似乎都必须绑定强类型的数据集,或者自己去写xsd文件xsd的数据集又大多都是绑定数据库的,没有直接和ex

.NET 2.0里强类型数据创建多层应用

创建|数据 .Net 2.0正式版的正式发布,对我们程序开发人员来说无疑是一件很大的喜事,已经很多的人开始了解并使用.NET 2.0.Visual Studio 2005 的一些新的增强功能和ADO.NET 2.0的新特性让我们开发高可伸缩的多层数据库应用程序更加简单和快捷.本文将带领大家使用Visual Studio 2005来创建一个N层数据库应用的示例,并介绍一些NET 2.0和 Visual Studio 2005相关的知识. 在.NET 1.1下就可以使用强类型数据集,可是在Visua

VS2005中使用强类型DataSet简化开发

在日常开发中,为了编写数据的增加.更新.修改.删除等功能而不得不面对枯燥的代码,做重复又重复的工作..NET 2.0正式版的发布,对我们程序开发人员来说无疑是一件很大的喜事,Visual Studio 2005 的一些新的增强功能和ADO.NET 2.0的新特性让我们开发高可伸缩的多层数据库应用程序更加简单和快捷. 在.NET 1.1下就可以使用强类型数据集,可是在Visual Studio 2003里开发起来还是有一些不方便,在Visual Studio 2005里对DataSet的设计视图做

在Visual Studio 2005和ASP.NET 2.0中使用强类型数据存取

asp.net|visual|数据 "Never put off until run time what can be done at compile time."David Gries, Compiler Construction for Digital Computers Introduction 作为程序员,我们在学习一些新技术的时候,范例有时候会是我们最大的敌人.指南通常被设计成简单易懂,但同时里面的懒惰.无效率的甚至是危险的代码编写会增多.像这种情况最普遍存在的就是在ADO.

数据集的结构定义与实例的关系(转)

数据 数据集的结构定义与实例的关系www.yescnet.com   CNET中文网 在.net的数据库开发中,不可避免的要使用到数据集(dataset),在阅读msdn学习数据集使用的时候,由于没有清晰的区分数据集的定义和实例,在操作中,总是这里做一个数据集,那里做一个数据集,绕来绕去,却不知所以然,待全部完成后,仔细思考一下, 才发现此数据集非彼数据集,其中一部分是数据集的定义,另一部分才是充满数据的数据集实例.因此为方便大家的理解,在这里将数据集的定义与实例分析一遍,以期有助于各位看客的.

编程语言漫谈

写在前边:我们知道现有语言的编程范式有:过程式,面向对象,函数式,逻辑式.随着软件工业化程度的普及,以及软件的复杂度越来越高,编程语言的发展历程也是从最初的过程式(命令式)语言c,发展到以java语言为代表的面向对象编程语言.而逻辑编程语言(以prolog为代表)和函数式语言(lisp系列)还多用在学术和人工智能领域中.近几年,随着多核,云计算时代的到来.函数式编程语言逐渐浮出水面,最经典的语言以scheme,common-lisp,ml,clojure,go为代表.而且最近的jdk8也逐步加入

.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)

阅读目录: 1.环路执行对象模型.碎片化执行模型(假递归式调用) 2.N层对象执行模型(纵横向对比链式扩展方法) 3.LINQ查询表达式和链式查询方法其实都是空壳子 4.详细的对象结构图(对象的执行原理) 5.IQueryable<T>与IQueryProvider一对一的关系能否改成一对多的关系 6.完整的自定义查询 1]. 环路执行对象模型.碎片化执行模型(假递归式调用) 这个主题扯的可能有点远,但是它关系着整个LINQ框架的设计结构,至少在我还没有搞懂LINQ的本意之前,在我脑海里一直频

ASP.NET2.0数据操作之创建业务逻辑层

asp.net|创建|数据 导言 本教程的第一节所描述的数据访问层(Data Access Layer,以下简称为DAL)已经清晰地将表示逻辑与数据访问逻辑区分开了.不过,即使DAL将数据访问的细节从表示层中分离出来了,可它却不能处理任何的业务规则.比如说,我们可能不希望产品表中那些被标记为"停用"的产品的"分类编号"或"供应商编号"被更新:我们还可能需要应用一些资历规则,比如说我们都不希望被比自己的资历还要浅的人管理.另外一个比较常见的情况就是

.NET环境下水晶报表使用总结

  水晶报表是一个优秀的报表开发工具,本人在开发通用管理系统的时候,所有报表都使用水晶报表,其简单.易用和强大的功能令笔者倍加喜爱,现将水晶报表使用手记呈现给大家. 一.在使用自带的水晶报表时,请注册,否则只能使用30次 水晶报表注册码 注册号:6707437608 密码:AAP5GKS0000GDE100DS 二.使用CrystalReportViewer进行预览 CrystalReportViewer控件允许在应用程序中查看 Crystal Report.ReportSource 属性用于设