.NET Framework 开发中的分层更新

注释

此类 DataSet 和相关类是 2000 年代初的旧版 .NET Framework 技术,使应用程序能够在应用与数据库断开连接时处理内存中的数据。 这些技术对于使用户能够修改数据并将更改保留回数据库的应用特别有用。 尽管数据集是经过证实的成功技术,但新 .NET 应用程序的建议方法是使用 Entity Framework Core。 Entity Framework 提供了一种更自然的方式来将表格数据用作对象模型,并且具有更简单的编程接口。

分层更新 是指在维护引用完整性规则的同时,将更新数据(包含两个或多个相关表的数据集)保存回数据库的过程。 引用完整性 是指数据库中约束提供的一致性规则,这些规则控制插入、更新和删除相关记录的行为。 例如,根据引用完整性,在允许为该客户创建订单之前,应强制创建客户记录。 有关数据集中关系的详细信息,请参阅 数据集中的关系

分层更新功能使用 TableAdapterManager 管理类型化数据集中的 TableAdapter。 组件 TableAdapterManager 是 Visual Studio 生成的类,而不是 .NET 类型。 将表从 “数据源 ”窗口拖到 Windows 窗体或 WPF 页面时,Visual Studio 会将 TableAdapterManager 类型的变量添加到窗体或页面中,并在组件托盘的设计器中看到该变量。 有关 TableAdapterManager 类的详细信息,请参阅 TableAdapters 的 TableAdapterManager参考节。

默认情况下,数据集将相关表视为“关系”,这意味着它不会强制实施外键约束。 可以使用 数据集设计器在设计时修改该设置。 选择两个表之间的关系线以显示“ 关系 ”对话框。 此处所做的更改将决定 TableAdapterManager 在将相关表中的变更发送回数据库时的行为。

在数据集中启用分层更新

默认情况下,将为在项目中添加或创建的所有新数据集启用分层更新。 通过将数据集中类型化数据集的分层更新属性设置为 TrueFalse,打开或关闭分层更新

分层更新设置

在表之间创建新关系

若要在两个表之间创建新关系,请在数据集设计器中选择每个表的标题栏,然后右键单击并选择“ 添加关系”。

分层更新添加关系菜单

了解外键约束、级联更新和删除

请务必了解如何在生成的数据集代码中创建数据库中的外键约束和级联行为。

默认情况下,数据集中的数据表使用与数据库中的关系匹配的关系(DataRelation)生成。 但是,数据集中的关系不会作为外键约束生成。 实际上,DataRelation 会配置为“仅限关系”,且没有 UpdateRuleDeleteRule

默认情况下,即使数据库关系设置为启用级联更新或级联删除,这些功能也仍然是关闭的。 例如,创建新客户和新订单,然后尝试保存数据可能会导致与数据库中定义的外键约束冲突。 有关详细信息,请参阅 在填充数据集时关闭约束

设置执行更新的顺序

设置更新操作的顺序可确定分别执行的插入、更新和删除操作的顺序,这些操作是为保存数据集中所有表中的所有修改数据而必要的。 启用分层更新后,首先执行插入,然后更新,然后删除。 TableAdapterManager 提供一个 UpdateOrder 属性,该属性可以设置为先执行更新,然后插入,然后删除。

注释

请务必了解更新顺序是全面包容的。 也就是说,执行更新时,将对数据集中的所有表执行插入和删除作。

若要设置UpdateOrder属性,将项从数据源窗口拖到窗体后,请选择TableAdapterManager组件托盘中的项,然后在UpdateOrder窗口中设置该属性。

在执行分层更新之前创建数据集的备份副本

在保存数据时(通过调用 TableAdapterManager.UpdateAll() 方法),TableAdapterManager 会尝试在单个事务中更新每个表的数据。 如果任何表的更新的任何部分失败,则会回退整个事务。 在大多数情况下,回滚会将应用程序返回到其原始状态。

但是,有时可能需要从备份副本还原数据集。 使用自动递增值时,可能会出现此问题的一个示例。 例如,如果保存操作不成功,则数据集中不会重置自动增量值,数据集将继续创建自动增量值。 这会在编号方面留下一个在应用程序中可能不可接受的空白。 如果出现问题,则 TableAdapterManager 提供一个 BackupDataSetBeforeUpdate 属性,该属性将现有数据集替换为备份副本(如果事务失败)。

注释

TableAdapterManager.UpdateAll方法运行时,备份副本仅在内存中。 因此,此备份数据集没有编程访问,因为它要么替换原始数据集,要么在 TableAdapterManager.UpdateAll 方法完成运行后超出范围。

修改生成的保存代码以执行分层更新

通过调用 TableAdapterManager.UpdateAll 该方法并传入包含相关表的数据集的名称,将数据集中相关数据表的更改保存到数据库。 例如,运行 TableAdapterManager.UpdateAll(NorthwindDataset) 此方法,将 NorthwindDataset 中所有表的更新发送到后端数据库。

“数据源 ”窗口中删除项后,代码会自动添加到 Form_Load 事件中以填充每个表( TableAdapter.Fill 方法)。 代码还会添加到 “保存 ”按钮单击事件 BindingNavigator ,以将数据从数据集保存回数据库(方法 TableAdapterManager.UpdateAll )。

生成的保存代码还包含调用该方法的代码 CustomersBindingSource.EndEdit 行。 更具体地说,它调用添加到窗体的第一个 EndEditBindingSource 方法。 也就是说,此代码只是为从“数据源”窗口拖到窗体上的第一个表生成的EndEdit 调用将提交当前正在编辑的任何数据绑定控件中的所有更改。 因此,如果数据绑定控件仍处于焦点状态,并且单击“保存”按钮,则该控件中所有未完成的编辑内容将在实际保存之前提交(通过 TableAdapterManager.UpdateAll 方法)。

注释

“数据集设计器”只为放置到窗体上的第一个表添加 代码BindingSource.EndEdit。 因此,您必须在窗体中为每个相关的表添加一行代码以调用 BindingSource.EndEdit 方法。 对于本演练,这意味着你必须添加一个对 OrdersBindingSource.EndEdit 方法的调用。

  1. 双击代码编辑器中打开 BindingNavigator“保存”按钮。

  2. 添加一行代码以在调用OrdersBindingSource.EndEdit方法的行之后调用CustomersBindingSource.EndEdit方法。 “保存”按钮单击事件中的代码应如下所示:

    this.Validate();
    this.customersBindingSource.EndEdit();
    this.ordersBindingSource.EndEdit();
    this.tableAdapterManager.UpdateAll(this.northwindDataSet);
    

除了在将数据保存到数据库之前对相关子表提交更改之外,你可能还必须在向数据集添加新子记录之前提交新创建的父记录。 换句话说,可能需要将新的父记录(Customer)添加到数据集,然后外键约束才能将新的子记录(Orders)添加到数据集。 为此,可以使用子 BindingSource.AddingNew 事件。

注释

是否需要提交新的父记录,取决于用于绑定数据源的控件类型。 本演练使用个别控件绑定到父表。 这需要额外的代码来提交新的父记录。 如果父记录被显示在像DataGridView这样的复杂绑定控件中,则不需要对父记录进行额外的EndEdit调用。 这是因为控件的基础数据绑定功能处理新记录的提交。

添加代码以在添加新子记录之前在数据集中提交父记录

  1. OrdersBindingSource.AddingNew 事件创建事件处理程序。

    • 在设计视图中打开 Form1,在组件托盘中选择 OrdersBindingSource,在“属性”窗口中选择“事件”,然后双击 AddNew 事件。
  2. 向调用该方法 CustomersBindingSource.EndEdit 的事件处理程序添加一行代码。 事件处理程序中的 OrdersBindingSource_AddingNew 代码应如下所示:

    this.customersBindingSource.EndEdit();
    

TableAdapterManager 引用

默认情况下,创建包含相关表的数据集时会生成类 TableAdapterManager 。 若要防止生成类,请将数据集属性的值 Hierarchical Update 更改为 false。 将具有关系的表拖到 Windows 窗体或 WPF 页面的设计图面上时,Visual Studio 将声明类的成员变量。 如果不使用数据绑定,则必须手动声明变量。

TableAdapterManager 类不是 .NET 类型。 因此,无法在文档中查找它。 它是在设计时创建的,作为数据集创建过程的一部分。

以下是类的常用方法和属性 TableAdapterManager

成员 DESCRIPTION
UpdateAll 方法 保存所有数据表中的所有数据。
BackUpDataSetBeforeUpdate 属性 确定是否在执行TableAdapterManager.UpdateAll方法之前创建数据集的备份副本。布尔值。
tableName 属性TableAdapter 表示 TableAdapter。 生成的 TableAdapterManager 属性包含其管理的每个 TableAdapter 属性。 例如,具有 Customers 和 Orders 表的数据集将生成包含 TableAdapterManagerCustomersTableAdapter 属性的 OrdersTableAdapter
UpdateOrder 属性 控制单个插入、更新和删除命令的顺序。 将此设置为枚举中的 TableAdapterManager.UpdateOrderOption 值之一。

默认情况下,UpdateOrder 被设置为 InsertUpdateDelete。 这意味着,对数据集中的所有表执行插入、更新和删除作。