[ADO.NET] 数据集中浏览多个相关表

来源:互联网 发布:淘宝手机秒杀在哪里找 编辑:程序博客网 时间:2024/05/16 07:36
  
     摘要:ADO.NET 中的数据集是一种在内存中表示数据的方法,它可以包含多个相关的数据表。本文介绍了在数据集中浏览这些相关数据表的方法。您将在 Visual Basic® .NET 或 Visual C#™ .NET 中创建一个 Windows® 应用程序,基于选定的记录返回相关记录,并使用表达式列为相关记录生成合计信息。本文包含一些指向英文站点的链接。
   
  简介
  由于数据集可以包含几个相关的表,因此了解如何在父记录和子记录之间进行浏览是一项基本任务,而这并非显而易见,特别是当您试图访问相关层次结构中的深层表中的数据时,更是如此。您还将学习如何浏览包含具有多对多关系的表的数据集,其中每个表都通过第三方表(中间表)彼此相关联。
   
  以下是本文所包含任务的概述:
   
  创建 Windows 应用程序项目。
  显示用作初始选定内容的数据列表。
  返回与选定记录相关的记录。
  浏览多个表和多个相关结构,并在运行时直接访问数据集中的数据。
  此外,本文还介绍一些相关的任务:
   
  为数据表添加基于相关数据的表达式列。
  生成相关数据的合计信息。
  前提条件
  要充分理解本文,您应该具有:
   
  基本的关系数据库概念的知识。
  与罗斯文示例数据库的有效连接,以便您能够创建和运行应用程序。
  大体上熟悉 ADO.NET 数据集。
  重要的数据对象
  要使用数据集中的相关记录,您应基本了解 .NET 框架 System.Data 命名空间中的几个对象以及它们如何相互作用。这些对象协同工作以提供数据集中的导航功能。
   
  以下对象用于表达数据集中的关系:
   
  DataSet - 在内存中表示数据,可以包含多个可与 DataRelation 对象相关的 DataTable 对象。
  DataTable - 表示一个完整的数据表。数据表的架构是由构成该表的 DataColumnCollection 定义的。当两个数据表相关时,DataRelation 对象使用每个表中的 DataColumn 来关联数据。
  DataRelation - 连接多个表,以便浏览相关表中的记录。访问相关记录时,DataRelation 对象被传递给 GetChildRows 或 GetParentRow 方法。DataRelation 对象确定所要查询的相关表,以便返回与 GetChildRows 或 GetParentRow 方法调用相关联的相关数据。
  DataRow - 表示数据的一个单独的记录。用于返回相关数据的 GetChildRows 方法和 GetParentRow 方法是 DataRow 对象的成员。
  DataColumn - 表示一个单独的字段,结合在一起时将定义 DataTable 的架构。当两个数据表相关时,DataRelation 对象使用每个表中的数据列来关联数据。

     创建应用程序
  本节将建立这一演练的起点。随后的步骤将创建数据连接、数据适配器和包含相关表的数据集,以及几个选择和显示数据的控件。
   
  创建新的 Windows 应用程序
   
  从 File(文件)菜单中,指向 New(新建),并选择 Project(项目)。将显示 New Project(新建项目)对话框。
  在 Project Types(项目类型)窗格中,根据您需要的编程语言,选择 Visual Basic Projects(Visual Basic 项目)或 Visual C# Projects(Visual C# 项目)。
  在 Templates(模板)窗格中,选择 Windows Application(Windows 应用程序),并将其命名为 DataRelationExample,然后单击 OK(确定)。
  DataRelationExample 项目将添加到 Solution Explorer(解决方案资源管理器)中。
   
  连接到数据库
  此连接允许您与 Visual Studio® 集成开发环境 (IDE) 中的数据源进行通讯。
   
  连接到 Server Explorer(服务器资源管理器)中的罗斯文示例数据库
   
  在 Server Explorer(服务器资源管理器)中,建立连接到罗斯文示例数据库的数据连接。
  在 Server Explorer(服务器资源管理器)中展开罗斯文数据连接,直到可以看到所有的表。
  创建数据适配器和连接
  此步骤创建用于在应用程序和数据源之间连接和交换数据的连接和数据适配器。
   
  创建数据适配器和连接
   
  将“客户”表从 Server Explorer(服务器资源管理器)中拖到窗体上。组件栏中将显示连接和数据适配器。
  选择 Connection(连接)并将 Name 属性设置为 dcNorthwind。
  选择数据适配器并将 Name 属性设置为 daCustomers。
  将“订单”表从 Server Explorer(服务器资源管理器)中拖到窗体上。组件栏中将显示第二个数据适配器。
  选择新的数据适配器并将 Name 属性设置为 daOrders。
  生成数据集
  使用刚刚添加到窗体上的数据适配器生成包含客户表和订单表的数据集。
   
  生成将包含相关数据表的数据集
   
  从 Data(数据)菜单中,选择 Generate Dataset(生成数据集)。将显示 Generate Dataset(生成数据集)对话框。
  提示:将光标移到窗体上即可使用 Data(数据)菜单。
  单击 New(新建)并将数据集命名为 dsNorthwind。
  选择客户表和订单表。
  选择 Add this dataset to the designer(将此数据集添加到设计器)复选框,然后单击 OK(确定)。
  Solution Explorer(解决方案资源管理器)的项目中将添加一个名为 dsNorthwind.xsd 的文件,并且组件栏中将显示该数据集的一个实例。
   
  创建关系
  生成数据集并不能自动创建数据集中各表之间的关系。关系可以通过编程创建,也可以使用 XML Designer(XML 设计器)直观地创建。本文使用 XML Designer(XML 设计器)。
   
  创建客户表和订单表之间的关系
   
  在 Solution Explorer(解决方案资源管理器)中,双击 dsNorthwind.xsd 文件。文件将在 XML Designer(XML 设计器)中打开。
  从工具栏的 XML Schema(XML 架构)选项卡中,将 Relation(关系)拖到订单表上。
  在 Edit Relation(编辑关系)对话框中,设置以下属性:
   
  元素 设置
  Name CustomersOrders
  Parent Customers
  Child Orders
  Key Fields CustomerID
  Foreign Key Fields CustomerID
   
   
  单击 OK(确定)以创建关系并关闭对话框。
  从 File(文件)菜单中,选择 Save All(全部保存)以保存该项目。
        显示数据
  此应用程序使用组合框、列表框和 RTF 文本框来选择和显示数据。
   
  添加选择和显示数据的控件
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1(.cs 或 .vb,取决于应用程序的语言),然后从快捷菜单中选择 View Designer(视图设计器)。
  在窗体的左半部,添加一个 ListBox 控件,并将其 Name 属性设置为 lbOrders。
  在窗体的右半部,添加一个 RichTextBox 控件,并将其 Name 属性设置为 rtbDetails。
  在列表框的上方,添加一个 ComboBox 控件,并将其 Name 属性设置为 cbCustomers。
  保存项目。
   
   
  图 1:建议的窗体控件布局
   
  现在,可以开始向应用程序添加功能了。
   
  设置显示公司名称的组合框
   
  选择组合框 (cbCustomers) 并设置以下属性: 属性 设置
  DataSource DsNorthwind1
  DisplayMember Customers.CompanyName
  ValueMember Customers.CustomerID
   
  用数据填充表
  要用数据填充表,必须为应用程序添加代码。
   
  在数据集 (dsNorthwind1) 中的客户表和订单表中填充数据
   
  双击窗体上的一块空白区域,为 Form1_Load 事件创建事件处理程序。
  添加以下代码:
   
  ' Visual Basic
  Private Sub Form1_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load
  ' 关闭数据集中的约束。
  DsNorthwind1.EnforceConstraints = False
  ' 用数据填充表。
  daOrders.Fill(DsNorthwind1)
  daCustomers.Fill(DsNorthwind1)
   
  ' 重新开启约束。
  DsNorthwind1.EnforceConstraints = True
  End Sub
   
  // C#
  private void Form1_Load(object sender, System.EventArgs e)
  {
  // 关闭数据集中的约束。
  dsNorthwind1.EnforceConstraints = false;
   
  // 用数据填充表。
  daOrders.Fill(dsNorthwind1);
  daCustomers.Fill(dsNorthwind1);
   
  // 重新开启约束。
  dsNorthwind1.EnforceConstraints = true;
  }
   
   
   
  保存项目。
  按 F5 键运行该应用程序。现在组合框中包含一个公司名称列表。
  关闭窗体。
  在两个表中浏览相关记录
  这里简要介绍一下如何在数据集中构成一对多关系的两个表之间访问数据。在选择一个数据行之后,可以通过调用 GetChildRows 或 GetParentRow 方法并向该数据行传递适当的数据关系来返回其相关记录。
   
  注意:GetChildRows 方法将以 DataRow 对象数组的形式返回数据,而 GetParentRow 方法只返回一个单个的数据行。
  要演示这一功能,需要给应用程序添加一些代码,以返回组合框中选定客户的所有订单(子行)。更改组合框中的选定客户会引发 ComboBox.SelectedIndexChanged 事件,列表框中将填充该选定客户的每个订单的订单 ID。
   
  您可以根据组合框中选定的客户,调用 GetChildRows 方法。订单表中的所有相关记录都将分配给名为 draOrders 的数据行数组。
   
  注意:下一节将添加在列表框中显示相关订单列表的功能。为确认数组中确实包含相关的记录,数组的长度(即选定客户的订单总数)将显示为窗体的标题。
  创建获取选定客户的订单的事件处理程序
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Designer(视图设计器)。
  双击组合框为 SelectedIndexChanged 事件创建事件处理程序。
  添加以下代码:
   
  ' Visual Basic
  Private Sub cbCustomers_SelectedIndexChanged _
  (ByVal sender As System.Object, ByVal e As System.EventArgs) _
  Handles cbCustomers.SelectedIndexChanged
  ' 声明一个用来保存选定客户的客户 ID 的字符串。
  Dim SelectedCustomerID As String
  SelectedCustomerID = cbCustomers.SelectedValue.ToString()
  ' 声明一个用来保存选定客户的记录的数据行。
  Dim drSelectedCustomer As DataRow
  drSelectedCustomer = _
  DsNorthwind1.Customers.FindByCustomerID _
  (SelectedCustomerID)
  ' 声明一个用来保存相关记录的数据行数组。
  Dim draOrders As DataRow()
  draOrders = drSelectedCustomer.GetChildRows("CustomersOrders")
  ' 在窗体标题中显示数组的长度(订单数)
  ' 和客户 ID。
  Me.Text = draOrders.Length.ToString() & " 订单所有者 " & _
  SelectedCustomerID
  End Sub
   
  // C#
  private void cbCustomers_SelectedIndexChanged
  (object sender, System.EventArgs e)
  {
  // 声明一个用来保存选定客户的客户 ID 的字符串。
  String SelectedCustomerID;
  SelectedCustomerID = cbCustomers.SelectedValue.ToString();
   
  // 声明一个用来保存选定客户的记录的数据行。
  DataRow drSelectedCustomer;
  drSelectedCustomer =
  dsNorthwind1.Customers.FindByCustomerID(SelectedCustomerID);
   
  // 声明一个用来保存相关记录的数据行数组。
  DataRow[] draOrders;
  draOrders = drSelectedCustomer.GetChildRows("CustomersOrders");
   
  // 在窗体标题中显示数组的长度(订单数)
  // 和客户 ID。
  this.Text = draOrders.Length.ToString() +
  " 订单所有者 " + SelectedCustomerID;
  }
   
   
   
  保存项目。
  运行应用程序。
  选择另一个客户,并检查窗体标题。将显示选定客户的订单总数及其客户 ID。
   
  关闭窗体。

     显示相关记录
  现在您已经有了选定客户的相关记录(存储在数据行数组中),您可以显示它们以便与用户进行交互。应用程序将逐一访问 GetChildRows 方法返回的数据行数组中的数据,并将每个相关记录的“订单 ID”作为单独的项添加到列表框中。
   
  注意:虽然此示例将逐一访问相关数据行数组中的数据,但列表框可能已经使用属性窗口,通过 DataSource 属性、DataMember 属性和 ValueMember 属性被绑定到相关的记录。
  在列表框中显示相关记录
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  在前面步骤中创建的组合框的 SelectedIndexChanged 事件处理程序中,将以下代码添加到处理程序中已有代码之下:
   
  ' Visual Basic
  ' 当更改选定客户时,清除订单列表。
  lbOrders.Items.Clear()
  rtbDetails.Text = ""
  ' 将每个相关订单的订单 ID 添加到列表框中。
  Dim drOrder As DataRow
  For Each drOrder In draOrders
  lbOrders.Items.Add(drOrder("OrderID"))
  Next
   
  // C#
  // 当更改选定客户时,清除订单列表。
  lbOrders.Items.Clear();
  rtbDetails.Text = "";
   
  // 将每个相关订单的订单 ID 添加到列表框中。
  foreach(DataRow drOrder in draOrders)
  {
  lbOrders.Items.Add(drOrder["OrderID"]);
  }
   
   
   
   
  保存项目。
  运行应用程序。
  列表框中将显示订单列表。在组合框中选择另一个客户,订单列表将被更新。
   
  关闭窗体。
  在三个或更多表中浏览相关记录
  浏览三个或更多表与处理两个表一样简单。要了解如何处理两个以上的表,请将订单明细表和产品表添加到 dsNorthwind 数据集中。在列表框中选定一个订单后,该订单的详细信息即显示在 RTF 文本框中。
   
  为了满足约束规则,您需要删除现有的数据关系,将来再重新创建。
   
  暂时删除 dsNorthwind 数据集中的 DataRelation
   
  在 Solution Explorer(解决方案资源管理器)中,双击 dsNorthwind.xsd 以在 XML Designer(XML 设计器)中打开它。
  选择现有的 CustomersOrders 关系并将其删除。
  保存项目。
  现在您需要将另外两个表添加到现有数据集中,并创建新的 DataRelation 对象以将所有表连在一起。
   
  将订单明细表和产品表添加到 dsNorthwind 数据集中
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Designer(视图设计器)。
  将“订单明细”表从 Server Explorer(服务器资源管理器)中拖到窗体上。组件栏中将显示一个新的数据适配器。
  选择该新的数据适配器并将其 Name 属性设置为 daOrderDetails。
  将“产品”表从 Server Explorer(服务器资源管理器)中拖到窗体上。组件栏中将显示一个新的数据适配器。
  选择该新的数据适配器并将其 Name 属性设置为 daProducts。
  新表只是被添加到了窗体上,因此每次添加额外的表时,都必须重新生成数据集。
   
  重新生成 dsNorthwind 数据集
   
  从 Data(数据)菜单中,选择 Generate Dataset(生成数据集)。
  提示:将光标移到窗体上即可使用 Data(数据)菜单。
  单击 Existing(现有),然后选择 dsNorthwind 数据集。
  选择所有四个表(客户表、订单表、订单明细表和产品表)。
  清除 Add this dataset to the designer(将此数据集添加到设计器)复选框,然后单击 OK(确定)。将生成带有附加表的数据集。
  注意:如果出现一个对话框,其中说明“The file has been modified outside of the source editor. Do you want to reload it?”(文件已在源编辑器之外被修改。是否要重新加载?),请单击 Yes(是)。
  请记住,生成数据集并不能自动创建数据集中各表之间的关系。
   
     创建关系
   
  在 Solution Explorer(解决方案资源管理器)中,双击 dsNorthwind.xsd 文件。文件将在 XML Designer(XML 设计器)中打开。
  从工具栏的 XML Schema(XML 架构)选项卡中,将 Relation(关系)拖到订单表上。
  在 Edit Relation(编辑关系)对话框中,设置以下属性:
   
  元素 设置
  Name CustomersOrders
  Parent Customers
  Child Orders
  Key Fields CustomerID
  Foreign Key Fields CustomerID
   
   
  单击 OK(确定)以创建关系并关闭对话框。
  从工具栏的 XML Schema(XML 架构)选项卡中,将 Relation(关系)拖到订单明细表上。
  在 Edit Relation(编辑关系)对话框中,设置以下属性:
   
  元素 设置
  Name OrdersOrderDetails
  Parent Orders
  Child OrderDetails
  Key Fields OrderID
  Foreign Key Fields OrderID
   
   
  单击 OK(确定)以创建关系并关闭对话框。
  从工具栏的 XML Schema(XML 架构)选项卡中,将 Relation(关系)拖到订单明细表上。
  在 Edit Relation(编辑关系)对话框中,设置以下属性:
   
  元素 设置
  Name ProductsOrderDetails
  Parent Products
  Child OrderDetails
  Key Fields ProductID
  Foreign Key Fields ProductID
   
   
  单击 OK(确定)以创建关系并关闭对话框。
  保存项目。
  订单明细表和产品表已被添加到数据集中,但是您仍需要添加代码,以便在运行时用数据来填充它们。
   
  用数据填充表
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  在 Form1_Load 事件处理程序中,将以下代码添加到注释“用数据填充表”与 daOrders.Fill(dsNorthwind1) 行之间:
   
  ' Visual Basic
  daOrderDetails.Fill(dsNorthwind1)
  daProducts.Fill(dsNorthwind1)
  // C#
  daOrderDetails.Fill(dsNorthwind1);
  daProducts.Fill(dsNorthwind1);
   
   
   
  用数据填充 RTF 文本框
  现在您要为项目添加代码,以便在列表框中选定某个订单时,可以在 RTF 文本框中显示所有订单明细。
   
  以下代码将基于列表框中的选定订单调用 GetChildRows 方法。订单明细表中的所有相关记录都将分配给名为 draOrderDetails 的数据行数组。每个数据行的内容将显示在 RTF 文本框中。
   
  注意:请注意嵌套的 For Each 循环是如何首先选取一个数据行,然后在该数据行的所有列中循环以访问整个相关记录的。
  设置 RTF 文本框以显示所有订单明细
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Designer(视图设计器)。
  双击列表框为列表框 lbOrders 的 SelectedIndexChanged 事件创建事件处理程序。
  添加以下代码:
   
  ' Visual Basic
  Private Sub lbOrders_SelectedIndexChanged _
  (ByVal sender As System.Object, ByVal e As System.EventArgs) _
  Handles lbOrders.SelectedIndexChanged
  ' 选择新订单时,清除 RTF 文本框。
  rtbDetails.Clear()
  ' 声明一个用来保存选定的订单 ID 的整数。
  Dim SelectedOrderID As Integer
  ' 将选定的项目设置为整数。
  SelectedOrderID = CType(lbOrders.SelectedItem, Integer)
   
  ' 声明一个用来保存选定订单的记录的数据行。
  Dim drSelectedOrder As DataRow
  drSelectedOrder = _
  DsNorthwind1.Orders.FindByOrderID(SelectedOrderID)
   
  ' 声明一个用来保存相关记录的数据行数组。
  Dim draOrderDetails() As DataRow
  draOrderDetails = _
  drSelectedOrder.GetChildRows("OrdersOrderDetails")
   
  Dim details As String = ""
  Dim drDetails As DataRow
  Dim dcDetails As DataColumn
  For Each drDetails In draOrderDetails
  For Each dcDetails In drDetails.Table.Columns
  details &= dcDetails.ColumnName & ": "
  details &= drDetails(dcDetails).ToString()
  details &= ControlChars.CrLf
  Next
  details &= ControlChars.CrLf
  Next
  rtbDetails.Text = details
  End Sub
   
  // C#
  private void lbOrders_SelectedIndexChanged
  (object sender, System.EventArgs e)
  {
  // 选择新订单时,清除 RTF 文本框。
  rtbDetails.Clear();
   
  // 声明一个用来保存选定的订单 ID 的整数。
  int SelectedOrderID;
  // 将选定的项目设置为整数。
  SelectedOrderID = (int)lbOrders.SelectedItem;
   
  // 声明一个用来保存选定订单的记录的数据行。
  DataRow drSelectedOrder;
  drSelectedOrder =
  dsNorthwind1.Orders.FindByOrderID(SelectedOrderID);
   
  // 声明一个用来保存相关记录的数据行数组。
  DataRow[] draOrderDetails;
  draOrderDetails =
  drSelectedOrder.GetChildRows("OrdersOrderDetails");
   
  string details = "";
  foreach(DataRow drDetails in draOrderDetails)
  {
  foreach(DataColumn dcDetails in drDetails.Table.Columns)
  {
  details += dcDetails.ColumnName + ": ";
  details += drDetails[dcDetails].ToString() + "/n";
  }
  details += "/n";
  }
  rtbDetails.Text = details;
  }
   
   
   
  保存项目。
  运行应用程序。
  在列表框中选择一个订单,其订单明细将显示在 RTF 文本框中。
  在列表框中选择另一个订单。RTF 文本框中的订单明细将被更新。
  浏览多对多关系
  构成多对多关系的表通常通过保证数据完整性的第三方表进行连接。在罗斯文数据库中,订单表和产品表就是这样相关的。因为有些订单可能包含很多产品,而有些产品又在很多订单中销售。这两个表是通过订单明细表连接的,订单明细表利用这两个表中的列建立自己特定的列,并使这些数据相关。浏览构成多对多关系的三个表与处理一对多关系的表并没有太大区别。
   
  要浏览多对多关系,您可以基于订单明细表中的单个记录来访问产品,这将返回产品名称并显示在订单明细中。
   
  您可以使用 GetParentRow 方法从产品表中访问产品名称。调用 GetParentRow 方法将返回单个数据行,而调用 GetChildRows 方法将返回数据行数组(如上例所示)。
   
  从订单明细记录中获取产品名称
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  在列表框 (lbOrders) 的 SelectedIndexChanged 事件处理程序中,将以下代码添加到 For Each 行之间:
   
  ' Visual Basic
  details &= "产品名称: " & _
  CType(drDetails.GetParentRow("ProductsOrderDetails") _
  ("ProductName"), String) & ControlChars.CrLf
  // C#
  details += "产品名称: " +
  drDetails.GetParentRow("ProductsOrderDetails")["ProductName"]
  + "/n";
   
   
   
  保存项目。
  运行应用程序。
  在列表框中选择一个订单,
  RTF 文本框中将显示产品名称和详细信息。现在窗体中显示来自所有四个表的相关数据。
   
   
   
  图 2:显示产品名称和订单明细的窗体
   
  在列表框中选择另一个订单。RTF 文本框中的订单明细将被更新。
  关闭窗体。      表达式列
  除了包含静态数据外,还可以基于表达式的结果为 DataColumn 分配值。表达式是一个分配给 DataColumn.Expression 属性的字符串。
   
  当表达式与相关数据一同使用时,数据列可以包含:
   
  相关数据列的计算所得值。
  相关数据列的合计信息。
  相关数据的逻辑比较结果。
  为说明处理相关数据时的值表达式列,我们将针对每种使用情况介绍一个示例,并添加到 DataRelationExample 应用程序中。
   
  添加包含计算值的表达式列
  计算的列包含数学运算结果。可以从现有的列中取值进行计算。订单明细表中将添加一个名为 Total 的新列,它将包含由表达式 UnitPrice * Quantity 返回的值(订单的总计美元值)。
   
  添加表达式列
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  将以下代码添加到 Form1_Load 事件处理程序中已有代码之上:
   
  ' Visual Basic
  ' 在订单明细表中创建名为 Total 的表达式列。
  Dim dcTotal as DataColumn = new DataColumn("Total")
  dcTotal.DataType = System.Type.GetType("System.Decimal")
  dcTotal.Expression = "UnitPrice * Quantity"
  DsNorthwind1.Order_Details.Columns.Add(dcTotal)
  // C#
  // 在订单明细表中创建名为 Total 的表达式列。
  DataColumn dcTotal = new DataColumn("Total");
  dcTotal.DataType = System.Type.GetType("System.Decimal");
  dcTotal.Expression = "UnitPrice * Quantity";
  dsNorthwind1.Order_Details.Columns.Add(dcTotal);
   
   
   
  运行应用程序。
  在列表框中选择一个订单,
  检查 RTF 文本框中的订单明细,并注意每个记录都有一个新的 Total 列,显示 UnitPrice 和 Quantity 字段的乘积。
   
  关闭窗体。
  添加包含合计信息的表达式列
  Expression 属性支持几个合计功能(Sum、Avg、Count 等)。有关详细信息,请参阅 DataColumn.Expression 属性。
   
  为演示如何生成合计信息,需要在订单表中添加一个名为 OrderTotal 的新列。此列将使用 Sum 功能,根据在列表框 (lbOrders) 中选定的订单返回所有子订单明细记录的总计美元值。然后,该值将显示在 RTF 文本框中每个订单明细的上方。
   
  创建 OrderTotal 列
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  在 Form1_Load 事件处理程序中,将以下代码添加到在订单明细表中创建 Total 列的代码的下方:
   
  ' Visual Basic
  ' 在订单表中创建名为 OrderTotal 的表达式列。
  Dim dcOrderTotal as DataColumn = new DataColumn("OrderTotal")
  dcOrderTotal.DataType = System.Type.GetType("System.Decimal")
  dcOrderTotal.Expression = "Sum(Child.Total)"
  DsNorthwind1.Orders.Columns.Add(dcOrderTotal)
  // C#
  // 在订单表中创建名为 OrderTotal 的表达式列。
  DataColumn dcTotal2 = new DataColumn("OrderTotal");
  dcTotal2.DataType = System.Type.GetType("System.Decimal");
  dcTotal2.Expression = "Sum(Child.Total)";
  dsNorthwind1.Orders.Columns.Add(dcTotal2);
   
   
   
  将合计信息显示在所有订单明细的上方
   
  在 lbOrders_SelectedIndexChanged 事件处理程序中,将以下代码添加到 Dim details As String = "" 或 string details = "" 行之下:
   
  ' Visual Basic
  details = "订单总计: " & String.Format("{0:c}", _
  DsNorthwind1.Orders.FindByOrderID(CType(lbOrders.SelectedItem, _
  Integer))("OrderTotal")) & ControlChars.CrLf
  // C#
  details = "订单总计: " +
  String.Format("{0:c}",dsNorthwind1.Orders.FindByOrderID
  ((int)lbOrders.SelectedItem)["OrderTotal"]) + "/n";
   
   
  运行应用程序。
  在列表框中选择一个订单,
  请注意,选定订单的所有订单明细的总计金额将显示在 RTF 文本框中的第一行。
   
  在列表框中选择另一个订单,将更新显示以反映新选择的订单。
  关闭窗体。
  添加包含逻辑求值的表达式列
  Expression 属性可以基于其他列中的计算值来填充某个数据列。例如,订单表中的 OrderSize 列可以包含值“Big”(如果订单总额大于 1000)或者“Small”(如果订单总额小于 1000)。
   
  为演示这类表达式,需要在 DataRelationExample 应用程序中添加代码以执行以下操作:
   
  在订单表中添加名为 OrderSize 的数据列。
  根据相关订单明细的值来填充 OrderSize 列。
  在 RTF 文本框的顶部同时显示 OrderSize 列的值和 OrderTotal 的值。
  添加创建 OrderSize 列的代码
   
  在 Solution Explorer(解决方案资源管理器)中,右键单击 Form1 并从快捷菜单中选择 View Code(查看代码)。
  在 Form1_Load 事件处理程序中,将以下代码添加到在订单表中创建 OrderTotal 列的代码的下方:
   
  ' Visual Basic
  ' 在订单表中创建名为 OrderSize 的表达式列。
  Dim dcOrderSize as DataColumn = new DataColumn("OrderSize")
  dcOrderSize.DataType = System.Type.GetType("System.String")
  dcOrderSize.Expression = "IIF(Sum(Child.Total)<1000,'Small','Big')"
  DsNorthwind1.Orders.Columns.Add(dcOrderSize)
  // C#
  // 在订单表中创建名为 OrderSize 的表达式列。
  DataColumn dcOrderSize = new DataColumn("OrderSize");
  dcOrderSize.DataType = System.Type.GetType("System.String");
  dcOrderSize.Expression = "IIF(Sum(Child.Total)<1000,'Small','Big')";
  dsNorthwind1.Orders.Columns.Add(dcOrderSize);
   
   
  显示 OrderSize 的值
   
  在 lbOrders_SelectedIndexChanged 事件处理程序中,将以下代码添加到第一个 For Each 行的上方:
   
  ' Visual Basic
  details &= " (" & CType(DsNorthwind1.Orders.FindByOrderID _
  (CType(lbOrders.SelectedItem, Integer))("OrderSize"), String) & ")" _
  & ControlChars.CrLf
  // C#
  details += " (" + dsNorthwind1.Orders.FindByOrderID
  ((int)lbOrders.SelectedItem)["OrderSize"] + ")/n";
   
   
   
  运行应用程序。
  在列表框中选择一个订单。
  检查 RTF 文本框中的第一行。选定订单的 OrderSize 将显示在 OrderTotal 的右侧。
  在列表框中选择另一个订单,将更新显示以反映新选择的订单。
  从 Debug(调试)菜单中,选择 Stop Debugging(停止调试)。
  有关相关表的其他信息
  这里有必要提及一些其他信息以丰富本文的内容。
   
  填充相关数据表的顺序非常重要
  相关数据表的填充顺序对数据的输出有很大影响,因此必须在设计应用程序时予以考虑。例如,请注意最后一个填充的客户表的情况。当填充客户表时,组合框将填充客户名称值。填充组合框时,会引发 SelectedIndexChanged 事件。这将执行事件处理程序中的代码。由于尚未填充订单表,GetChildRows 方法将返回零 (0) 个记录,窗体的标题将显示错误信息。试一试:更改代码以首先填充客户表,并运行应用程序。窗体的标题显示 ALFKI 的零 (0) 个订单,这是不正确的。
   
  返回相关记录的特定版本
  通过将所需的 DataRowVersion 作为第二个(可选的)参数传递给 GetChildRows 或 GetParentRow 方法,可以返回数据行的特定版本。以该应用程序为例,如果只想查看特定客户的原始订单,可以将组合框的 SelectedIndexChanged 事件中的代码更改为类似如下的代码。由于此应用程序中的数据并未更改,以下代码不会产生明显的效果,这里只是作为一个说明。
   
  ' Visual Basic
  ' 只用选定客户的原始子行
  ' 填充数组。
  Dim draOrders As DataRow() = DsNorthwind1.Customers.FindByCustomerID _
  (cbCustomers.SelectedValue.ToString()).GetChildRows _
  ("CustomersOrders", DataRowVersion.Original)
  // C#
  // 只用选定客户的原始子行
  // 填充数组。
  DataRow draOrders = dsNorthwind1.Customers.FindByCustomerID
  (cbCustomers.SelectedValue.ToString()).GetChildRows
  ("CustomerOrders", DataRowVersion.Original);
   
   
  总结
  要访问特定数据行的相关记录,可以调用该行的 GetChildRows 或 GetParentRow 方法,以传递连接该数据行及其相关记录的数据关系。然后,便可以通过检查由该方法调用返回的数据行(或数据行数组)来访问相关的记录。
   
  通过为 DataColumn.Expression 属性分配一个有效的表达式字符串并将数据列添加到相应的 DataTable.Columns 集合中,可以对相关记录中的值进行计算,合计和逻辑求值。