演练:创建 N 层数据应用程序
“N 层”数据应用程序是指用于访问数据且分为多个逻辑层的应用程序。 通过将应用程序组件分离到相对独立的层中,可以提高应用程序的可维护性和可伸缩性。 该结构之所以具有这种优点,是因为它有利于采用可应用于单个层而无需重新设计整个解决方案的新技术。 N 层体系结构包括一个表示层、一个中间层和一个数据层。 中间层通常包括数据访问层、业务逻辑层和共享组件(例如身份验证和验证)。 数据层则包括关系数据库。 N 层应用程序通常将敏感信息存储在中间层的数据访问层中,目的是将它们与访问表示层的最终用户隔离。 有关更多信息,请参见 N 层数据应用程序概述。
在 N 层应用程序中,分离各层的一种方法是为要包括在应用程序中的每一层创建相互独立的项目。 类型化数据集包含一个 DataSet Project 属性,该属性决定了生成的数据集和 TableAdapter 代码应归属到哪些项目中。
本演练演示如何使用**“数据集设计器”**将数据集和 TableAdapter 代码分离到相互独立的类库项目中。 分离数据集和 TableAdapter 代码后,您将创建 Visual Studio 中的 Windows Communication Foundation 服务和 WCF 数据服务 服务以调入数据访问层。 最后,您要创建一个 Windows 窗体应用程序并将其用作表示层。 该层将访问数据服务中的数据。
在本演练中,您将执行以下步骤:
新建将包含多个项目的 N 层解决方案。
向 N 层解决方案中添加两个类库项目。
使用**“数据源配置向导”**创建类型化数据集。
将生成的 TableAdapter 和数据集代码分离到相互独立的项目中。
创建 Windows Communication Foundation (WCF) 服务以调入数据访问层。
在服务中创建从数据访问层检索数据的函数。
创建 Windows 窗体应用程序来充当表示层。
创建绑定到数据源的 Windows 窗体控件。
编写填充数据表的代码。
有关本主题的视频版本,请参见 Video How to: Creating an N-Tier Data Application(视频帮助:创建 N 层数据应用程序)。
系统必备
若要完成本演练,您需要:
- 能够访问 Northwind 示例数据库。 有关更多信息,请参见如何:安装示例数据库。
创建 N 层解决方案和用于保存数据集的类库 (DataEntityTier)
本演练的第一步是创建一个解决方案和两个类库项目。 第一个类库将用于保存数据集(生成的类型化 DataSet 类以及将保存应用程序数据的数据表)。 此项目将用作应用程序的数据实体层,它通常位于中间层内。 数据集设计器用于创建初始数据集,并自动将代码分离到两个类库中。
提示
请确保已正确命名项目和解决方案,然后再单击“确定”。 这样做将有助于完成本演练。
创建 N 层解决方案和 DataEntityTier 类库
从**“文件”**菜单创建一个新的项目。
提示
Visual Basic 和 C# 项目都支持使用“数据集设计器”。 请使用这两种语言之一创建新项目。
在**“新建项目”对话框的“项目类型”窗格中,单击“Windows”**。
单击**“类库”**模板。
将项目命名为“DataEntityTier”。
将解决方案命名为“NTierWalkthrough”。
单击**“确定”**。
随即将创建一个包含 DataEntityTier 项目的 NTierWalkthrough 解决方案,并将其添加到**“解决方案资源管理器”**中。
创建用于保存 TableAdapter 的类库 (DataAccessTier)
创建 DataEntityTier 项目后,下一步是创建另一个类库项目。 此项目将保存生成的 TableAdapter,它称为应用程序的“数据访问层”。 数据访问层包含连接到数据库所需的信息,通常位于中间层内。
创建用于 TableAdapter 的新类库
在**“文件”**菜单上,向 NTierWalkthrough 解决方案添加一个新项目。
在**“新建项目”对话框的“模板”窗格中,单击“类库”**。
将项目命名为 DataAccessTier 并单击**“确定”**。
随即将创建 DataAccessTier 项目并将其添加到 NTierWalkthrough 解决方案中。
创建数据集
下一步是创建类型化数据集。 类型化数据集通过单个项目中的数据集类(包括 DataTable 类)和 TableAdapter 类创建 (所有这些类都将生成到单个文件中)。在将数据集和 TableAdapter 分离到不同的项目中时,移到另一个项目中的是数据集类,TableAdapter 类则留在原始项目中。 因此,应在最终包含 TableAdapter 的项目(DataAccessTier 项目)中创建数据集。 在本演练中,您将使用**“数据源配置向导”**创建数据集。
提示
必须具有访问 Northwind 示例数据库的权限才能创建连接。 有关如何设置 Northwind 示例数据库的信息,请参见如何:安装示例数据库。
创建数据集
在**“解决方案资源管理器”**中单击 DataAccessTier。
在**“数据”菜单上,单击“显示数据源”**。
在**“数据源”窗口中,单击“添加新数据源”启动“数据源配置向导”**。
在**“选择数据源类型”页上,单击“数据库”,然后单击“下一步”**。
在**“选择您的数据连接”**页上执行下列操作之一:
如果下拉列表中包含与 Northwind 示例数据库的数据连接,请单击该连接。
- 或 -
单击**“新建连接”以打开“添加连接”**对话框。 有关更多信息,请参见“添加/修改连接”对话框(通用)。
如果数据库需要密码,请选择该选项以包括敏感数据,再单击**“下一步”**。
提示
如果选择了本地数据库文件(而不是连接至 SQL Server),系统可能会询问是否将该文件添加到项目中。 请单击“是”,以便将该数据库文件添加到项目中。
在**“将连接字符串保存到应用程序配置文件中”页上单击“下一步”**。
在**“选择数据库对象”页面上展开“表”**节点。
单击**“Customers”和“Orders”表的复选框,然后单击“完成”**。
NorthwindDataSet 将被添加到 DataAccessTier 项目中并显示在**“数据源”**窗口内。
将 TableAdapter 与数据集分离
创建数据集后,接着是要将生成的数据集类与 TableAdapter 分离。 通过将**“数据集项目”**属性设置为要用于存储分离出的数据集类的项目的名称,可以达到此目的。
将 TableAdapter 与数据集分离
在**“解决方案资源管理器”中双击“NorthwindDataSet.xsd”,以便用“数据集设计器”**打开该数据集。
单击设计器上的空白区域。
在**“属性”窗口中查找“数据集项目”**节点。
在**“数据集项目”列表中,单击“DataEntityTier”**。
在**“生成”菜单上,单击“生成解决方案”**。
数据集和 TableAdapter 将被分离到两个类库项目中。 最初包含整个数据集 (DataAccessTier) 的项目现在只包含 TableAdapter。 **“数据集项目”**属性中指定的项目 (DataEntityTier) 则包含类型化数据集:NorthwindDataSet.Dataset.Designer.vb(或 NorthwindDataSet.Dataset.Designer.cs)。
提示
分离数据集与 TableAdapter 时(通过设置“数据集项目”属性),将不会自动移动项目中现有的数据集分部类。 您必须手动将它们移到数据集项目中。
创建新的服务应用程序
由于本演练演示如何使用 WCF 服务访问数据访问层,因此需要创建一个新的 WCF 服务应用程序。
创建新的 WCF 服务应用程序
在**“文件”**菜单上,向 NTierWalkthrough 解决方案添加一个新项目。
在**“新建项目”对话框的“项目类型”窗格中,单击“WCF”。 在“模板”窗格中,单击“WCF 服务库”**。
将项目命名为 DataService 并单击**“确定”**。
随即将创建 DataService 项目并将其添加到 NTierWalkthrough 解决方案中。
在数据访问层中创建用于返回客户和订单数据的方法
数据服务需要调用数据访问层中的两个方法:GetCustomers 和 GetOrders。 这些方法将返回 Northwind 的 Customers 表和 Orders 表。 请在 DataAccessTier 项目中创建 GetCustomers 和 GetOrders 方法。
在数据访问层中创建返回 Customers 表的方法
在**“解决方案资源管理器”**中,双击 NorthwindDataset.xsd 以在数据集设计器中打开该数据集。
右击 CustomersTableAdapter,然后单击**“添加查询”**以打开 TableAdapter 查询配置向导。
在**“选择命令类型”页上,保留“使用 SQL 语句”的默认值,然后单击“下一步”**。
在**“选择查询类型”页上,保留“SELECT (返回行)”的默认值,然后单击“下一步”**。
在**“指定 SQL SELECT 语句”页上,保留默认查询并单击“下一步”**。
在**“选择要生成的方法”页的“返回 DataTable”部分的“方法名称”**中,键入 GetCustomers。
单击**“完成”**。
在数据访问层中创建返回 Orders 表的方法
右击 OrdersTableAdapter,然后单击**“添加查询”**。
在**“选择命令类型”页上,保留“使用 SQL 语句”的默认值,然后单击“下一步”**。
在**“选择查询类型”页上,保留“SELECT (返回行)”的默认值,然后单击“下一步”**。
在**“指定 SQL SELECT 语句”页上,保留默认查询并单击“下一步”**。
在**“选择要生成的方法”页的“返回 DataTable”部分的“方法名称”**中,键入 GetOrders。
单击**“完成”**。
在**“生成”菜单上,单击“生成解决方案”**。
向数据服务中添加对数据实体和数据访问层的引用
由于数据服务需要数据集和 TableAdapter 中的信息,因此需要添加对 DataEntityTier 和 DataAccessTier 项目的引用。
向数据服务中添加引用
在**“解决方案资源管理器”中右击 DataService,然后单击“添加引用”**。
在**“添加引用”对话框中单击“项目”**选项卡。
同时选择**“DataAccessTier”和“DataEntityTier”**项目。
单击**“确定”**。
向服务中添加函数以调用数据访问层中的 GetCustomers 和 GetOrders 方法
现在数据访问层已包含返回数据的方法,接下来要在数据服务中创建调用这些方法的方法。
提示
对于 C# 项目,必须添加对 System.Data.DataSetExtensions 程序集的引用,才能编译下面的代码。
在数据服务中创建 GetCustomers 和 GetOrders 函数
在**“DataService”**项目中,双击 IService1.vb 或 IService1.cs。
在**“在此处添加服务操作”**注释下方添加下面的代码:
<OperationContract()> _ Function GetCustomers() As DataEntityTier.NorthwindDataSet.CustomersDataTable <OperationContract()> _ Function GetOrders() As DataEntityTier.NorthwindDataSet.OrdersDataTable
[OperationContract] DataEntityTier.NorthwindDataSet.CustomersDataTable GetCustomers(); [OperationContract] DataEntityTier.NorthwindDataSet.OrdersDataTable GetOrders();
在 DataService 项目中,双击 Service1.vb(或 Service1.cs)。
向 Service1 类中添加下面的代码:
Public Function GetCustomers() As DataEntityTier.NorthwindDataSet.CustomersDataTable Implements IService1.GetCustomers Dim CustomersTableAdapter1 As New DataAccessTier.NorthwindDataSetTableAdapters.CustomersTableAdapter Return CustomersTableAdapter1.GetCustomers() End Function Public Function GetOrders() As DataEntityTier.NorthwindDataSet.OrdersDataTable Implements IService1.GetOrders Dim OrdersTableAdapter1 As New DataAccessTier.NorthwindDataSetTableAdapters.OrdersTableAdapter Return OrdersTableAdapter1.GetOrders() End Function
public DataEntityTier.NorthwindDataSet.CustomersDataTable GetCustomers() { DataAccessTier.NorthwindDataSetTableAdapters.CustomersTableAdapter CustomersTableAdapter1 = new DataAccessTier.NorthwindDataSetTableAdapters.CustomersTableAdapter(); return CustomersTableAdapter1.GetCustomers(); } public DataEntityTier.NorthwindDataSet.OrdersDataTable GetOrders() { DataAccessTier.NorthwindDataSetTableAdapters.OrdersTableAdapter OrdersTableAdapter1 = new DataAccessTier.NorthwindDataSetTableAdapters.OrdersTableAdapter(); return OrdersTableAdapter1.GetOrders(); }
在**“生成”菜单上,单击“生成解决方案”**。
创建表示层以显示数据服务中的数据
现在,解决方案中的数据服务已具有调入数据访问层的方法,接下来要创建另一个项目,以调入数据服务并将数据显示给用户。 在本演练中,将创建一个 Windows 窗体应用程序;它将充当 N 层应用程序的表示层。
创建表示层项目
在**“文件”**菜单上,向 NTierWalkthrough 解决方案添加一个新项目。
在**“新建项目”对话框的“项目类型”窗格中,单击“Windows”。 在“模板”窗格中,单击“Windows 窗体应用程序”**。
将项目命名为 PresentationTier 并单击**“确定”**。
随即将创建 PresentationTier 项目并将其添加到 NTierWalkthrough 解决方案中。
将 PresentationTier 项目设置为启动项目
由于表示层是用于显示数据和进行数据交互的实际客户端应用程序,因此必须将 PresentationTier 项目设置为启动项目。
将新的表示层项目设置为启动项目
- 在**“解决方案资源管理器”中,右击“PresentationTier”,然后单击“设为启动项目”**。
向表示层中添加引用
客户端应用程序 PresentationTier 需要具有对数据服务的服务引用,才能访问服务中的方法。 另外,WCF 服务又需要具有对数据集的引用,才能启用类型共享。 而只有通过数据服务启用类型共享,表示层才能使用添加到数据集分部类中的代码。 由于数据表的行和列更改事件中通常添加有类似于验证的代码,因此可能需要从客户端访问此代码。 有关更多信息,请参见在 Visual Studio 中使用 WCF 服务。
向表示层添加引用
在**“解决方案资源管理器”中右击 PresentationTier,然后单击“添加引用”**。
在**“添加引用”对话框中单击“项目”**选项卡。
选择**“DataEntityTier”,然后单击“确定”**。
向表示层添加服务引用
在**“解决方案资源管理器”中右击 PresentationTier,然后单击“添加服务引用”**。
在**“添加服务引用”对话框中,单击“发现”**。
选择**“Service1”,然后单击“确定”**。
提示
如果当前计算机上存在多项服务,请选择您在本演练的前面部分中创建的服务(即包含 GetCustomers 和 GetOrders 方法的服务)。
向窗体中添加 DataGridView 以显示数据服务返回的数据
在添加对数据服务的服务引用后,将自动使用该服务返回的数据填充**“数据源”**窗口。
向窗体中添加两个数据绑定 DataGridView
在**“解决方案资源管理器”**中,选择 PresentationTier 项目。
在**“数据源”窗口中,展开“NorthwindDataSet”,然后定位到“Customers”**节点。
将**“Customers”**节点拖动到 Form1 上。
在**“数据源”窗口中,展开“Customers”节点,然后定位到相关的“Orders”节点(“Orders”节点嵌套在“Customers”**节点中)。
将相关的**“Orders”**节点拖动到 Form1 上。
双击窗体的空白区域,以创建一个 Form1_Load 事件处理程序。
将下面的代码添加到 Form1_Load 事件处理程序中。
Dim DataSvc As New ServiceReference1.Service1Client NorthwindDataSet.Customers.Merge(DataSvc.GetCustomers) NorthwindDataSet.Orders.Merge(DataSvc.GetOrders)
ServiceReference1.Service1Client DataSvc = new ServiceReference1.Service1Client(); northwindDataSet.Customers.Merge(DataSvc.GetCustomers()); northwindDataSet.Orders.Merge(DataSvc.GetOrders());
增加服务所允许的最大消息大小
由于服务会返回 Customers 和 Orders 表中的数据,而 maxReceivedMessageSize 的默认值还不够大,无法容纳这些数据,因此必须予以增加。 在本演练中,您将值更改为 6553600。 更改操作将在客户端上执行,此操作会自动更新服务引用。
提示
采用较小的默认大小,旨在降低遭受拒绝服务 (DoS) 攻击的可能性。 有关更多信息,请参见 MaxReceivedMessageSize。
增加 maxReceivedMessageSize 值
在**“解决方案资源管理器”**的 PresentationTier 项目中,双击 app.config 文件。
定位到**“maxReceivedMessage”**大小特性,然后将值更改为 6553600。
测试应用程序
运行该应用程序。 它会从数据服务中检索数据,并将检索到的数据显示在窗体上。
测试应用程序
按 F5。
应用程序会从数据服务中检索 Customers 和 Orders 表的数据,并将检索到的数据显示在窗体上。
后续步骤
根据应用程序的要求,在基于 Windows 的应用程序中保存相关数据后,可能还要执行一些步骤。 例如,您可以对此应用程序进行以下增强:
向数据集添加验证。 有关信息,请参见演练:向 N 层数据应用程序添加验证。
向应用程序添加本地数据库。 有关更多信息,请参见演练:向 N 层应用程序添加本地数据库缓存。
向服务中添加其他方法,以将数据更新回数据库。