`
yangyou230
  • 浏览: 1648015 次
文章分类
社区版块
存档分类

Visual Studio 2005 中的新 DataSet 特性

 
阅读更多

http://dev.csdn.net/develop/article/82/82837.shtm

简介
在之前的ADO.NET2.0中的新DataSet特性这篇文章中,我讨论了即将对ADO.NETDataSet类及其相关类(例如DataSet、DataTable和DataView)作出的一些改动以及这些类的增强功能。所有这些类都是属于Microsoft.NETFramework基类库的类。

本文,我将致力于在MicrosoftVisualStudio2005开发环境下使用这些类以及派生的类进行开发工作。对于类型化DataSet所作的更改和由VisualStudio2005生成的新类型化TableAdapter,是本文将要讨论的具体内容。除此之外,为开发以数据为中心的应用程序而使用的设计器和工具也是本文要讨论的内容,这些设计器和工具提供了很高的灵活性和工作效率。为了解释不同的概念和特性,我将逐步介绍开发人员在实现应用程序数据处理部分时通常要经历的过程。代码示例使用Northwind数据库,该数据库是MicrosoftSQLServer(以及MSDE)7.0版本和MicrosoftSQLServer2000自带的示例数据库。

返回页首
数据源
VisualStudio2005引入了项目数据源的概念。数据源代表在应用程序中可以使用的数据。数据库不是这些数据的唯一来源,定义数据源所使用的DataSourceConfigurationWizard允许您从三种不同的源获取数据:

1.
数据库—既可以是基于服务器的数据库(例如SQLServer或Oracle),也可以是基于文件的数据库(例如Access或SQLServerExpress)。VisualStudio自动生成类型化DataSet及其他类,并将它们添加到项目。

2.
对象—任何具有公共属性的对象都可以是数据源。不一定非要实现某个特殊接口。

3.
Web服务—从Web服务创建的数据源,将创建与Web服务返回的数据类型相对应的对象。


数据源具有事半功倍的作用。一方面,它可以使指定、设计和生成代表应用程序数据的强类型类更容易。另一方面,它提供一种灵活而统一的机制,可非常快速地构建功能丰富、运行高效的WinForm和WebForms用户界面。在阅读本文的过程中,您将了解到这是多么得快速、简单和灵活。

数据库(DataSet)数据源的创建及其在WinForms应用程序中的使用是本文的重点内容。但是,以下两点也不容忽视:

•一旦创建了数据源,就将以相同的方式使用每个数据源,而无需考虑其数据来自何处。也就是说,就像您可以轻松地将基于Database的数据源(以图形方式)绑定到网格控件或一组控件上一样,真正来自Web服务或您自定义业务对象的数据也要绑定到控件上。

•无论是在WinForms还是在WebForms应用程序中使用,数据源均以同一种方式进行定义。不同的数据提供程序也进行了抽象,以便在只使用DataSets和TableAdapters公开数据访问的情况下,只需更改连接字符串并重新生成类就可以更改实际使用的数据库。


类型化DataSet和TableAdapter

数据库数据源就是一个强类型DataSet与一个或多个强类型DataTables和TableAdapters对的组合。类型化DataSet的概念并不陌生,在VisualStudio2002/2003中就已经提出。虽然它是从.NETFramework的一般DataSet类派生的生成类,但它具有定义好的架构以及特定于该架构的属性和方法。与此同时,DataSet中的每个表还要生成其他三个特定于该DataSet的派生类—DataTable、DataRow和DataRowChangeEvent类。在这些类中,每个类都有针对相关表的特定架构、属性和方法。例如,如果根据NorthwindEmployees表定义一个数据源,最终将生成以下类:

•NorthwindDataSet

•EmployeesDataTable

•EmployeesDataRow

•EmployeesRowChangeEvent


这四个类就组成了一个类型化DataSet。在VisualStudio2005中还将生成第五个类,名为EmployeesTableAdapter的类型化TableAdapter,稍后我们将讨论这个类。当然,如果您以动态方式定义查询,那么就不能生成类型化DataSet,而是需要使用标准的DataSet。

为什么要为类型化DataSet而烦恼呢?因为除了促使您预先考虑数据的架构,而非仓促决定之外,类型化DataSet还提供了一些实际的优点:

1.
DataSets、DataTables、DataRows和RowChangeEvent都特定于正在处理的架构。

2.
表、列和关系是以命名的属性方式公开的,而非一般的集合元素。

3.
由于(2)的原因,VisualStudio代码编辑器将支持完整的智能感知和语句结束支持。

4.
可以实现编译时类型检查,例如在编译时而不是等到运行时就可以捕捉到字段名拼写错误,这同样是由于(2)的原因。

5.
代码更简洁,可读性更强。例如以下代码行:

country=dsNorthwind.Tables("Employees").Rows(row)("Country")

可以替换为

country=dsNorthwind.Employees(row).Country



总而言之,类型化DataSets所提供的设计时和编译时支持不但可以大大地减少启动开发时间,而且可以减少调试和稳定应用程序所需的时间。

此外,TableAdapter是VisualStudio2005新提出的概念。它意味着强类型TableAdapter就是标准DataAdapter的强类型等价类。您可以使用TableAdapter连接到数据库,执行对数据库的查询或存储过程,并将数据填写到相关的DataTable。每个DataTable-TableAdapter对都以一个TableAdapter指代。

TableAdapter实质上就是一个标准的DataAdapter的外部包装程序,它提供以下一些好处:

•同一个TableAdapter类可在多个窗体或组件上使用,因此任何对查询/命令进行的更改都将自动在所有实例中反映出来。这不同于现有情形,在现有情形下,每个访问数据库的组件都必须拥有各自单独配置的DataAdapter。但是如果要确保DataTables和DataAdapters保持同步,这样做将更容易。

•如果要为某个指定的DataTable定义多个查询/命令,使用一个TableAdapter即可轻松完成,而不必使用多个DataAdapters或手动切换代码。

•Fill命令的名字可读性强、较友好,而且TableAdapter包含的代码可以自动为这些命令方法中的所有参数填加类型和值信息。您再也不需要将其以特定于提供程序的数据类型(例如SqlInt)进行传递了。


举一个简单的代码片断示例会有助于解释这些特性。在VisualStudio2002/2003中,即使使用了类型化DataSet,执行一个带有两个参数的简单查询也需要不少的代码。对于下列查询

SELECTFirstName,LastNamefromEmployeesWHERECountry=@countryANDCity=@city

我们必须按以下方式编写代码:

Me.SqlAdapter1.SelectCommand.Parameters("@country").value=
Me.CountryListbox.SelectedValue.Trim()
Me.SqlAdapter1.SelectCommand.Parameters("@city").value=
Me.CityTextbox.Text.Trim()
Me.SqlAdapter1.Fill(Me.NorthwindDataSet.Employees)

毫无疑问,随着参数数量的增长,代码行数也将不断增加。但更重要的是,正确地记忆和输入所有参数名的机率却大大降低了。即使准确记住了参数名,也仍然需要记住参数的数据类型。这还不是最糟糕的情况,如果错误地输入了字段名或者为值赋了错误的类型,那么很可能到运行时才会察觉。

如果使用VisualStudio2005中的TableAdapter,一旦定义了命令FillByCountryAndCity,在任何地方使用它时只需编写一行代码,将其以参数值形式传递即可:

Me.EmployeesTableAdapter.FillByCountryAndCity(_
Me.NorthwindDataSet.Employees,Me.CountryListbox.SelectedValue.Trim(),
_Me.CityTextbox.Text.Trim())

不容忽视的是,我们不仅可以从一个TableAdapter那里取得多个命名命令,而且这些命令都是强类型的。这就意味着在VisualStudio中编写代码时,可以将这些命令视为TableAdapter的方法,因为我们获得了完整的智能感知。我们还要对这些命令的参数进行编译时类型检查,同时,方法和参数类型定义的工具提示也可以助我们一臂之力。TableAdapter可以包含多个执行不同命令、接收不同参数的方法。现在我们要构建示例窗体,稍后再详细介绍TableAdapter。

开始行动—创建数据源

本文,我们将构建一个显示Northwind数据库中每个定单定购信息的窗体。打开一个新的VisualBasicWinForms项目后,首先必须做的事情是向项目中添加一个新数据源(在创建这一示例的过程中,我们将使用VisualBasic,但所有的操作对于C#也适用)。

添加一个数据源:

1.
在VisualStudio主菜单中,选择Data菜单项中的ShowDataSources,即可显示数据源窗口(在该窗口未显示出来的情况下)。

2.
在数据源窗口上,单击AddNewDataSource工具栏按钮。该操作将启动DataSourceConfigurationWizard,该向导将DataAdapterConfigurationWizard的大部分功能和VisualStudio2002/2003中的DataSet生成工具结合在一起。

3.
如果您的VisualStudio版本仍然包含向导的欢迎页面,请选择Next。然后将显示ChooseaDataSourceType页面。

4.
选择Database。

5.
选择Next,显示ChooseYourDataConnection页面。

6.
选择NewConnection,显示AddConnection对话窗口。

7.
输入要连接到SQLServer(或MSDE)实例以及Northwind数据库所需的信息。

8.
选择OK,关闭对话窗口。

9.
注意,现在的连接字符串是保存为一个设置属性,可以通过下列语句访问

My.Settings.NorthwindConnectionString

在C#中,该语句为以下形式

VSDataSets.Properties.Settings.Default.NorthwindConnectionString;


10.
选择Next,显示ChooseYourDatabaseObjects页面。

11.
注意,可以选择TablesViews、Stored、Procedures或Functions。

展开Tables节点,然后选择Orders和OrderDetails表。我们将使用表中的所有列,但您也可以只选择应用程序所需的那些列。

12.
选择Finish,退出向导。


图1显示OrderDetails表展开后的数据源窗口,图中显示了该表的所有列。

按此在新窗口打开图片

图1.数据源窗口中的OrderDetails表


如果要作出一些改动,重新输入DataSourceConfigurationWizard,可以选择数据源窗口工具栏的ConfigureDataSetwithWizard,或者右键单击该窗口中任何元素,从得到的上下文菜单中选择向导。然而,编辑生成的DataSet和(多个)TableAdapter更好的工具是DataSetDesigner。

DataSet设计器

VisualStudio2005包含的DataSetDesigner是一个专门为指定和编辑DataSets及其相关TableAdapters而设计的工具。与VisualStudio2002/2003中的情形比较,它有了明显的改进,因为以前我们必须使用XML架构编辑器来定义强类型DataSets。在这里,DataSet和TableAdapter的定义仍然保存在.XSD文件中,如果一定要编辑XML架构,也仍然是使用XML编辑器。不过,相似之处仅此而已。而且这样做只是为了文件格式方便起见,并不是为了使DataSetDesigner支持任意的XSD文件。

选择数据源窗口工具栏中的EditDataSetwithDesigner,或者右键单击该窗口中任何元素,从得到的上下文菜单中选择使用设计器进行编辑,将进入DataSet设计器。在设计DataSets及其DataTables的过程中,设计者很可能会觉得该工具与过去设计数据库使用的其他工具十分相似。要为连接的数据库添加表,可以将数据库对象(例如表、视图、存储过程)从ServerExplorer中拖放到设计器表面,或者在设计器上下文菜单的Data主菜单选项中选择AddTableAdapter,启动TableAdapterConfigurationWizard。因为DataSet还可以包含不与数据库连接而直接加载的表,所以还可以选择菜单中的AddDataTable来添加一个单独的表。在编辑器中同样可以添加和/或重命名列。另一个干净利落的特性是,编辑器自动识别数据库中各表之间的关系,在DataSet中为您定义各表之间对应的Relations。

图2显示在DataSet设计器中,由Orders和OrderDetails表组成的数据源。注意,与每个DataTable密切相关的是其各自对应的TableAdapter,用于为表填写数据,或者(可选)用改动后的数据更新数据库。


按此在新窗口打开图片

图2.数据源中的Orders和OrderDetails表


TableAdapterConfigurationWizard

选择Data主菜单中的AddQuery或Configure(一个现有查询),或者在设计器中右键单击TableAdapter,从得到的上下文菜单中选择这两项,可以启动DataSet设计器中的TableAdapterConfigurationWizard。此向导等同于VisualStudio2002/2003的DataAdapterConfigurationWizard,只不过多了两个附加页面。一个是图3所示的ChooseaQueryType页面。由于TableAdapter汇集了针对给定表的所有命令,因此该页面允许您定义多个Select/Fill命令和查询—任何类型的查询都可以,例如Update、Insert、Delete或返回单个值类型的查询。切记,这些更新查询是TableAdapter的命名方法,必须直接调用。而且它们还是执行TableAdapter的Update方法时自动调用的更新查询,这与执行DataAdapter.Update方法一样。

向导中另一个增加的页面是ChooseMethodstoGenerate页。在该页中可以选择您所定义的每个查询/命令方法名(一个或多个)。向导为每个命令都提供一个Fill和Get方法,如图3所示。Fill要求提供需要填写数据的DataTable,而Get方法将返回填写后新创建的DataTable。


按此在新窗口打开图片

图3.ChooseMethodstoGenerate页面中的Fill和Get方法


按照典型的用法,您可以为一个TableAdapter定义多个Fill命令,它将返回同一种架构(多个列),只是WHERE子句不同而已。这也是默认情况下向导会为方法名提供一个FillBy和GetDataBy前缀的原因。不过,您当然可以选择任何名字作为方法名。

虽然TableAdapter可以包含多个Fill命令,但在调用其中的Update方法时却只能执行一组更新命令。这组命令根据TableAdapter的主查询自动生成。第一次创建TableAdapter时定义的查询被认为是它的主查询。如果随后定义的任何查询返回的架构与主查询的架构不同,则设计器将显示一个消息框进行提醒。另一方面,如果您修改了主查询的架构,VisualStudio将修改其他查询的架构以与之匹配。

通过TableAdapterConfigurationWizard添加新命令

现在,我们将另一个命令添加到Orders表的TableAdapter。

1.
选择数据源窗口工具栏中的EditDataSetwithDesigner,打开DataSet设计器。

2.
选择Orders表的TableAdapter,再从该表的上下文菜单中选择AddQuery。

3.
如果您的VisualStudio版本中仍然有Welcome页,请选择页面上的Next。之后,显示ChooseaCommandType页面。

4.
要接受默认的SQL语句,选择Next。这时显示ChooseaQueryType页面。

5.
要接受默认的SELECT语句,选择Next。然后,显示SpecifyaSQLSELECTStatement页面。

6.
输入下列SQL语句。

SELECTOrderID,CustomerID,EmployeeID,OrderDate,RequiredDate,
ShippedDate,ShipVia,Freight,ShipName,ShipAddress,ShipCity,
ShipRegion,ShipPostalCode,ShipCountry
FROMOrders
WHERECustomerID=@CustID

此后,返回由进行查询的@CustID参数指定的所有客户Orders。

7.
选择Next,显示ChooseMethodstoGenerate页。

8.
选中页面上的两个复选框。将方法名分别改为FillByCustomer和GetDataByCustomer。

9.
选择Next,然后选择Finish,完成该过程。


现在请您看一下DataSet设计器中的OrdersTableAdapter,这时出现了第二个命令对—FillByCustomer和GetDataByCustomer,CustomerID的值就是该命令的一个参数。那么,该方法的参数属于哪种.NET类型呢?让我们来讨论一下。

后台简介

在DataSet设计器或任何相关向导中进行修改时,VisualStudio都会为一组类型化的类生成代码。具体而言,它将生成以下类:

1.
DataSet类

2.
DataTable类

3.
TableAdapter类

4.
DataRow类

5.
DataRowChangeEvent类


除了DataSet类(每个数据源只有一个)之外,其余四个类对于DataSet中定义的表而言是相同的。可通过以下操作查看这些类的代码:

1.
在SolutionExplorer窗口中,单击工具栏上的ShowAllFiles按钮,显示与项目相关的所有文件。

2.
展开NorthwindDataSet.xsd文件的节点。

3.
双击文件节点上的NorthwindDataSet.Designer.vb。这就是为实现组成DataSet的那些类而生成的代码。

4.
打开代码窗口左上角的Listbox,将看到本文所用类的列表:

NorthwindDataSet


Order_DetailsDataTable
OrdersDataTable

Order_DetailsRow
OrdersRow

Order_DetailsRowChangeEvent
OrdersRowChangeEvent

Order_DetailsTableAdapter
OrdersTableAdapter


5.
选择左侧Listbox中的OrdersTableAdapter类。

6.
再选择右侧Listbox中的FillByCustomer方法。此时将显示该方法的代码,如下所示:


PublicOverloadsOverridableFunctionFillByCustomer(ByValdataTable
AsNorthwindDataSet.OrdersDataTable,ByValCustIDAsString)AsInteger
Me.Adapter.SelectCommand=Me.CommandCollection(1)
If(CustIDIsNothing)Then
ThrowNewSystem.ArgumentNullException("CustID")
Else
Me.Adapter.SelectCommand.Parameters(0).Value=CType(CustID,String)
EndIf
If(Me.m_clearBeforeFill=true)Then
dataTable.Clear
EndIf
DimreturnValueAsInteger=Me.Adapter.Fill(dataTable)
ReturnreturnValue
EndFunction




从该代码片断中我们可以了解几件事情。

•FillByCustomer方法实际上带有两个参数—一个是要填写的OrdersDataTable,另一个是字符串类型的CustID参数。

•不用检查完文件中的所有代码,我们就可以发现TableAdapter类维护着一个命令集合,正是从这个集合中自动将正确的命令指派给.NETDataAdapter,供其使用这些命令自动与数据库通讯。

•如果状态参数的AllowDBNull属性设置为False,该方法会不断检查是否有状态参数的实例传递进来。

•如果DataAdapter的SelectCommand属性已经配置好,则CustID的参数值将赋给该属性的参数。

•所有配置设置完毕后,即可调用DataAdapter.Fill()方法来填写OrdersDataTable。


切记,这些代码都不需要您动手编写。它们是已经生成并配置好的代码。花些时间查找一下为您生成的其他类。您将更深入、更广泛地理解这些类的实现方式,甚至还可能学到几个有用的编程技巧。

注尽管类型化DataSet及其相关类(包括TableAdapters)均在一个源文件中生成,但TableAdapters是在某个独立的命名空间中生成的。这说明应该将实体对象(DataSets)与真正的数据访问对象(TableAdapters)区分开来。

返回页首
构建以数据为中心的窗体
生成了类型化DataSet之后,接下来要构建一个显示其数据的窗体。对于.NETFramework2.0和VisualStudio2005中的WinForms以及数据绑定,我不会深入研究它们的所有细节和新特性(因为可研究的东西太多了),但如果要了解以下这方面所取得的一些进展—如何能更简单、更灵活地建立功能上以数据为中心的窗体,这到是一个难得的机会。

工具箱中的数据组件

如果您常常使用工具箱“Data”选项卡上的标准数据组件来构建以数据为中心的代码,那么打开VisualStudio2005后,可能会有些沮丧和担心,因为您无法找到它们。这当然是“设计”好的,Microsoft希望引导用户利用新的类型化DataSets和TableAdapters。如果实在想使用以前没有类型化的组件,您可以手动将它们添加到工具箱中。我强烈建议您不要将新的TableAdapters与部分类技术(新的类型化DataSets)一起使用;TableAdapters的使用和扩展更容易。

在VisualBasic的团队日记中,可以找到更多各种各样的设计决策信息以及这些决策的深层思想。

特别是您可以浏览一下SteveLasker的两篇文章:WhyaretheDataComponentsnolongerontheToolbox?和Whycan'tIdragfromServerExplorertomyform?。

在VisualStudio设计器中打开一个窗体时,VisualStudio工具箱会出现一个以项目名为标签的选项卡。在项目中添加一个数据源并至少将其编译一次后,该选项卡中将出现创建的DataSets和TableAdapters。您可以将这些组件拖放到窗体设计器上,在使用设计器实现数据访问组件的情况下,这是很好的做法,但通常情况下往往不这么做。而是使用以下三种不同方法中的一种来构建以数据为中心的窗体。首先,逐步介绍第一种方法,这种方法最简单,甚至可能最普遍。它就是所谓的“一次拖动”数据绑定。

1.
双击解决方案资源管理器中的Form1.vb,打开VisualStudio窗体设计器中的Form1。

2.
展开数据源窗口中的Orders表节点。

注意,DataSet中的每个表和每行列都有一个与之相关的图标。在将表或列拖放到窗体上时,这些图标表示用于绑定数据的WinForm控件类型(或者是“放置”类型)。从相关联的下拉列表中选择某个控件类型选项,再选择一个该类型的控件,可以改变控件类型。注意,该列表还包含None(显示为空)和自定义(指定您喜欢的任何控件)这两个选项。

仅在当前活动窗口是窗体(或组件)设计器时,这些图标和放置类型列表可见。此外,您不能在数据源窗口中拖放控件,图标的改变会指示出这一点。

3.
将Orders表的控件类型从DataGridView更改为Details。这就是说,将整个Orders表拖动到窗体上时,会构建一个每次显示一行详细信息的窗体,而不是显示网格中所有数据(一次显示所有行)的窗体。Details视图会为每个列都添加一个标签和一个控件,控件类型是在数据源窗口中指定的类型。

4.
将Orders表从数据源窗口拖动到设计器中的Form1。

5.
选择后七个(7)字段及其标签,将它们拖放到与前七个字段并排的位置上,这时的窗体外观如图4所示。



按此在新窗口打开图片

图4.设计器中的Form1


6.
启动应用程序,使用窗体顶部工具栏上的导航按钮逐个浏览记录,启动并确认应用程序可以正常运行。

接下来回顾一下将数据源表拖动到窗体上时VisualStudio的动作。查看窗体下面的组件栏,会看到它向窗体添加了四个组件。其中的两个组件NorthwindDataSet和OrdersTableAdapter我们已经熟悉了(您喜欢它们吗?)。OrdersTableAdapter用于将数据库中的数据填写到NorthwindDataSet的OrdersDataTable。甚至连执行Fill的一行代码也已经编写好,并自动添加到Form1的Load事件处理程序中了。

Me.OrdersTableAdapter.Fill(Me.NorthwindDataSet.Orders)



对于数据绑定至关重要的类是BindingSource类,在当前示例中,它被命名为含义清晰的OrdersBindingSource。BindingSource(在Beta1版本中称为DataConnector)提供将控件绑定到窗体所需的服务。它在数据源和绑定到其上的控件之间提供了一个中间层。通过设置BindingSource的DataSource和DataMember属性,可将它连接到数据源,然后将控件添加到控件的DataBindings集合中,从而将控件绑定到BindingSource。所有与数据的交互(例如,记录导航、排序、筛选和编辑)均通过BindingSource完成。此外,还允许通过List、Item和Current属性访问底层数据。

添加的另外一个组件是OrdersBindingNavigator。BindingNavigator类是提供标准用户界面的工具栏,用于导航和操作窗体上的数据。BindingNavigator(Beta1版本中称为DataNavigator)是一个具有一组预配置按钮的ToolStrip控件。它可以连接到BindingSource,将其作为自身的数据源,并且可以提供控制导航可用数据的工具栏按钮。如果您希望响应一些导航事件(而不是控制导航),那么应该挂钩BindingSource对象的事件。

构建主-从窗体

有了显示单个表数据的窗体之后,如果要以主-从形式显示另一个相关表,还会很容易吗?还是变得很难了?不如继续在Form1上完成下列步骤吧:

1.
现在我们将使用“连接点”数据绑定来构建窗体—将一个控件从工具箱中拖动到窗体并调整它的位置,然后将一个元素从数据源窗口中拖放到该控件上,从而将两者互相连接起来.

2.
选择工具箱中AllWindowsForms选项卡上的DataGridView控件。将其拖置到Form1并调整它的位置,使其占据窗体下半部分空间。

3.
返回到图5所示的数据源窗口,注意OrderDetails表实际上同时出现在该窗口中的两个位置。第一个位置是NorthwindDataSet的第一级子节点上,而且是Orders表的同辈节点。另一个位置是Orders表的子节点上,这表示它是相关的表。如果希望单独在窗体上显示OrderDetails表,可以选择NorthwindDataSet正下方OrderDetails表的匹配项。但在本示例中,我们希望显示OrderDetails表,因为它与主Orders表有关,所以我们选择Orders表正下方OrderDetails表的匹配项。



按此在新窗口打开图片

图5.数据源窗口中的OrderDetails表


4.
选择Orders表下方出现的OrderDetails表,将其拖动到Form1上的DataGridView。

5.
这时Order_DetailsBindingSource和Order_detailsTableAdapter已经添加到Form1的组件栏中。

6.
运行应用程序,使用BindingNavigator移动Orders表中的记录,如图6所示。注意观察DataViewGrid中显示的OrderDetails记录如何自动调整来只显示那些与当前Orders记录相关的记录。



按此在新窗口打开图片

图6.Orders表中BindingNavigator



返回页首
自定义生成代码
在前文中查看DataSet的类代码时,您可能注意到了事实上有两个VisualBasic代码文件—NorthwindDataSet.Designer.vb和NorthwindDataSet.vb。如果没有NorthwindDataSet.vb文件,请返回到DataSetDesigner并双击设计器背景,创建该文件。

这些文件都用于实现组成DataSet的类。使用两个文件是为了利用简单且功能非常强大的新特性—partialclasses。它是一个编译器功能,它允许在几个声明之间拆分类(或结构)的定义。不同的声明可能保存在不同的源代码文件中,只要声明都属于同一个程序集和命名空间就可以。VisualStudio广泛采用了该功能,从而将由设计器生成的某个类的代码与开发人员编写的该类的代码区分开来。在VisualStudio2002/2003中,所有窗体代码都是该窗体类声明的一部分,例如:

PublicClassForm1
InheritsSystem.Windows.Forms.Form

该窗体(包括窗体上放置的任何控件)的初始化代码由VisualStudio生成。这些代码位于InitComponent()方法中,默认情况下,该方法出现在名为“Windows窗体设计器生成代码”的代码区域中用户编写的代码之前。该区域通常关闭,这是为了尽量避免与您编写的代码搞混而分散您的注意力。在VisualStudio2005中,代码保存在Form1.Designer.vb这一完全不同的文件中,这将更有助于您集中注意力。此外,如果想查看该文件的内容,在该窗体中就可以—单击解决方案资源管理器工具栏上的ShowAllFiles,展开Form1.vb节点,然后双击Form1.Designer.vb,代码编辑器中将显示代码。文件Form1.vb只包含您(作为开发人员)为Form1类编写的代码。

至于DataSet及其相关类的代码,使用部分类和不同文件区分设计器代码和开发人员编写的代码则具有更重大的意义。这种区分不止可使代码更整洁,而且解决了在VisualStudio2002/2003中使用类型化DataSets时存在的一个主要问题。

通常,您还希望在为DataSet及其相关类自动生成的代码基础上进行扩展或添加,例如附加属性或自定义验证代码。那么,您可以放心地在生成代码中添加。只要不更改架构就可以,否则您需要重新生成DataSet代码。在VisualStudio2002/2003中,由于代码和生成代码都添加在某一个文件中,因此重新生成代码时将清除添加的代码。正是由于使用了部分类,VisualStudio2005才得以避免出现这种情况。新生成的代码将覆盖现有的设计器代码并保存在以.Designer.vb为扩展名的文件中,而.vb文件中开发人员编写的代码仍然完整无缺。

要扩展使用部分类的DataSet功能,一种方法是添加自定义的验证代码。这时可以在生成的类型化DataSet中添加一些应用程序逻辑。我们将自定义的验证代码和初始化添加到NorthwindDataSet中Orders表内增加的新行中。添加一个新行时,我们希望检查传递的邮政编码值是否与实际传递的城市相匹配。如果不是,则将ShipPostalCode字段的值更改为Invalid。假定实现了以下这样一个函数,该函数在给定的邮政编码与给定城市匹配的情况下返回True:

FunctionIsPostalCodeInCity(ByValPostalCodeasstring,ByValCityasstring)AsBoolean

通过以下方式可将该检验条件添加到NorthwindDataSet:

1.
选择数据源窗口工具栏中的EditDataSetwithDesigner,打开DataSet设计器。

2.
双击设计器背景的空白区域。在代码编辑器中打开文件NorthwindDataSet.vb。

3.
输入以下代码来替换默认代码:

PartialPublicClassNorthwindDataSet
PartialClassOrdersDataTable
ProtectedSubValidateNewRow(ByValsenderAsObject,_
ByValeAsSystem.Data.DataTableNewRowEventArgs)_
HandlesMe.TableNewRow
'Createastronglytypedinstanceoftherow
'Thishelpsusavoidcodeinquotes,
'eg,e.Row("ShipPostalCode")
DimordersRowAsNorthwindDataSet.OrdersRow
ordersRow=e.Row
IfNotordersRow.IsShipPostalCodeNullAnd_
NotordersRow.IsShipCityNullThen
IfNotIsPostalCodeInCity(ordersRow.ShipPostalCode,_
ordersRow.ShipCity)Then
'SetthevalueoftheShipPostalCode
ordersRow.ShipPostalCode="Invalid"
'Typically,changingausersdataisabaduserexperience
'SoindicateanerrorwiththeErrorProvider
'Weareillustratingbothapproacheshere
ordersRow.SetColumnError(_
ShipPostalCodeColumn.ColumnName,"InvalidPostalCode")
Else
'wealwaysneedtoresettheerrorwhenthevalueisvalid
ordersRow.SetColumnError(_
ShipPostalCodeColumn.ColumnName,String.Empty)
EndIf
EndIf
EndSub
EndClass

PrivateSharedFunctionIsPostalCodeInCity(ByValpostalCodeAsString,_
ByValcityAsString)AsBoolean
'Thisisastub,justtocheckfunctionality
Ifcity="RiodeJaneiro"Then
ReturnFalse
Else
ReturnTrue
EndIf
EndFunction
EndClass



注意,DataSet的所有相关类(例如,OrdersDataTable)在其内部均作为嵌套类实现。前面代码中的部分类声明就反映了这一实现过程。

为了让错误提供程序来提示错误,以补充或代替将邮政编码值更改为Invalid这一操作,可执行以下步骤:

1.
将ErrorProvider控件从工具箱拖放到Form1,将其放置在“ShipPostalCode”文本框右侧。

2.
在ErrorProvider属性窗口中,将DataSource属性设置为OrdersBindingSource。


要查看验证代码的执行情况,可以运行应用程序并导航到城市为“里约热内卢”的那条记录,图7对此做出说明。


按此在新窗口打开图片

图7.错误提供程序控件


该示例仅示范如何轻松地扩展类型化DataSet及其相关类的功能,这里的相关类指由VisualStudio自动生成的类。您或许还希望在生成的类中添加一些其他的方法和属性。当设计应用程序以及使用DataSets时,您会想到多种多样的可能性。关键是要记住,由于在VisualStudio2005中可以使用部分类,您编写的代码是保存在另一个单独文件中的,因此重新生成DataSet类时您的代码不会受影响。

返回页首
小结
使用VisualStudio2005生成的类型化DataSets从未如此之简单而灵活。DataSetDesigner为定义DataSets而提供了一个更简单、更自然的工具。在DataSetDesigner内就可以配置新的TableAdapter类,使用该类提供的单一而集中的机制,能够轻松地维护和执行针对某个特定数据表的多个不同查询和命令。利用部分类编译器功能,可以分离设计器生成的代码和开发人员编写的代码,同时在重新生成DataSet类时,避免了对为扩展这些类而编写好任意自定义代码的影响。此外,新的.NET数据绑定类和机制在结合了VisualStudio2005内部提供的工具,从而使开发以数据为中心的应用程序更加快速、简便。

原文地址:http://www.microsoft.com/china/msdn/li ... vbnet/newdtastvs05.mspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics