演练:在 .NET Framework 应用程序的事务中保存数据

注释

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

本演练演示如何使用 System.Transactions 命名空间在事务中保存数据。 在本演练中,你将创建一个 Windows 窗体应用程序。 将使用数据源配置向导为 Northwind 示例数据库中的两个表创建数据集。 你将将数据绑定控件添加到 Windows 窗体,并修改 BindingNavigator 保存按钮的代码,以更新 TransactionScope 中的数据库。

先决条件

若要完成本教程,需要 .NET 桌面开发和数据存储以及处理 Visual Studio 中安装的工作负载。 若要安装它们,请打开 Visual Studio 安装程序,然后选择要修改的 Visual Studio 版本旁边的 修改(或 更多>修改)。 请参阅修改 Visual Studio

本演练使用 SQL Server Express LocalDB 和 Northwind 示例数据库。

  1. 如果没有 SQL Server Express LocalDB,请从 SQL Server Express 下载页或通过 Visual Studio 安装程序安装它。 在 Visual Studio 安装程序中,可以将 SQL Server Express LocalDB 作为 .NET 桌面开发 工作负载的一部分或作为单个组件进行安装。

  2. 按照以下步骤安装 Northwind 示例数据库:

    1. 在 Visual Studio 中,打开 SQL Server 对象资源管理器 窗口。 (SQL Server 对象资源管理器作为数据存储和处理工作负荷的一部分安装在 Visual Studio 安装程序中。)展开“SQL Server”节点。 右键单击 LocalDB 实例并选择“新建查询”

      此时会打开查询编辑器窗口。

    2. Northwind Transact-SQL 脚本 复制到剪贴板。 此 T-SQL 脚本从头开始创建 Northwind 数据库,并使用数据填充该数据库。

    3. 将 T-SQL 脚本粘贴到查询编辑器中,然后选择 “执行” 按钮。

      短时间后,查询将完成运行并创建 Northwind 数据库。

创建 Windows 窗体应用程序

第一步是创建 Windows 窗体应用(.NET Framework)。

  1. 在 Visual Studio 的“文件”菜单中,依次选择“新建”>“项目”。

  2. 在左侧窗格中展开 Visual C#Visual Basic ,然后选择 Windows 桌面

  3. 在中间窗格中,选择 Windows 窗体应用 项目类型。

  4. 将项目 SavingDataInATransactionWalkthrough 命名,然后选择 “确定”。

    项目 SavingDataInATransactionWalkthrough 已创建并已添加到 解决方案资源管理器

创建数据库数据源

此步骤使用 数据源配置向导 基于 Northwind 示例数据库中的 CustomersOrders 表创建数据源。

  1. 若要打开 “数据源 ”窗口,请在 “数据 ”菜单上选择“ 显示数据源”。

  2. “数据源 ”窗口中,选择“ 添加新数据源 ”以启动 数据源配置向导

  3. 在“ 选择数据源类型” 屏幕上,选择“ 数据库”,然后选择“ 下一步”。

  4. “选择数据连接 ”屏幕上执行以下作之一:

    • 如果下拉列表中提供了与 Northwind 示例数据库的数据连接,请选择它。

      -或-

    • 选择 “新建连接 ”以启动 “添加/修改连接 ”对话框,并创建与 Northwind 数据库的连接。

  5. 如果数据库需要密码,请选择包含敏感数据的选项,然后选择“ 下一步”。

  6. “将连接字符串保存到应用程序配置文件 ”屏幕上,选择“ 下一步”。

  7. “选择数据库对象 ”屏幕上,展开 “表” 节点。

  8. 选择CustomersOrders表,然后选择完成

    NorthwindDataSet 将添加到项目,并且表CustomersOrders将显示在“数据源”窗口中。

向窗体添加控件

通过将某些项从“数据源”窗口拖到窗体,可创建数据绑定控件

  1. “数据源 ”窗口中,展开 “客户 ”节点。

  2. 将主 “客户 ”节点从 “数据源 ”窗口拖到 Form1 上。

    用于导航记录的 DataGridView 控件和工具栏(BindingNavigator)将显示在窗体上。 NorthwindDataSetCustomersTableAdapterBindingSourceBindingNavigator出现在组件托盘中。

  3. 将相关的 “订单” 节点(不是主 “订单 ”节点,而是 “传真 ”列下方的相关子表节点)拖到 CustomersDataGridView 下方的窗体上。

    窗体上显示一个 DataGridView。 组件托盘中会显示一个OrdersTableAdapter和一个BindingSource

添加对 System.Transactions 程序集的引用

事务使用 System.Transactions 命名空间。 默认情况下不会添加对 system.transactions 程序集的项目引用,因此需要手动添加它。

添加对 System.Transactions DLL 文件的引用

  1. 在“项目”菜单中,选择“添加引用”。

  2. 选择 System.Transactions (在 .NET 选项卡上),然后选择“ 确定”。

    对 System.Transactions 的引用已添加到项目中。

修改 BindingNavigator 的 SaveItem 按钮中的代码

由于第一个表已放置在你的窗体上,因此代码会默认添加到 BindingNavigator 上保存按钮的 click 事件中。 需要手动添加代码来更新任何其他表。 在本演练中,我们将现有保存代码从保存按钮的单击事件处理程序中重构出来。 我们还创建一些方法,以便根据是否需要添加或删除行来提供特定的更新功能。

修改自动生成的保存代码

  1. 选择 CustomersBindingNavigator 上的“保存”按钮(带有软盘图标的按钮)。

  2. CustomersBindingNavigatorSaveItem_Click 方法替换为以下代码:

    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateData();
    }
    
    private void UpdateData()
    {
        this.Validate();
        this.customersBindingSource.EndEdit();
        this.ordersBindingSource.EndEdit();
    
        using (System.Transactions.TransactionScope updateTransaction = 
            new System.Transactions.TransactionScope())
        {
            DeleteOrders();
            DeleteCustomers();
            AddNewCustomers();
            AddNewOrders();
    
            updateTransaction.Complete();
            northwindDataSet.AcceptChanges();
        }
    }
    

协调相关数据更改的顺序如下:

  • 删除子记录。 (在此情况下,请从 Orders 表中删除记录。)

  • 删除父记录。 在本例中,请从 Customers 表中删除记录。

  • 插入父记录。 在此示例中,在 Customers 表中插入记录。

  • 插入子记录。 (在本例中,在 Orders 表中插入记录。)

删除现有顺序

  • 将以下 DeleteOrders 方法添加到 Form1

    private void DeleteOrders()
    {
        NorthwindDataSet.OrdersDataTable deletedOrders;
        deletedOrders = (NorthwindDataSet.OrdersDataTable)
            northwindDataSet.Orders.GetChanges(DataRowState.Deleted);
    
        if (deletedOrders != null)
        {
            try
            {
                ordersTableAdapter.Update(deletedOrders);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("DeleteOrders Failed");
            }
        }
    }
    

删除现有客户

  • 将以下 DeleteCustomers 方法添加到 Form1

    private void DeleteCustomers()
    {
        NorthwindDataSet.CustomersDataTable deletedCustomers;
        deletedCustomers = (NorthwindDataSet.CustomersDataTable)
            northwindDataSet.Customers.GetChanges(DataRowState.Deleted);
    
        if (deletedCustomers != null)
        {
            try
            {
                customersTableAdapter.Update(deletedCustomers);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("DeleteCustomers Failed");
            }
        }
    }
    

添加新客户

  • 将以下 AddNewCustomers 方法添加到 Form1

    private void AddNewCustomers()
    {
        NorthwindDataSet.CustomersDataTable newCustomers;
        newCustomers = (NorthwindDataSet.CustomersDataTable)
            northwindDataSet.Customers.GetChanges(DataRowState.Added);
    
        if (newCustomers != null)
        {
            try
            {
                customersTableAdapter.Update(newCustomers);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("AddNewCustomers Failed");
            }
        }
    }
    

添加新顺序

  • 将以下 AddNewOrders 方法添加到 Form1

    private void AddNewOrders()
    {
        NorthwindDataSet.OrdersDataTable newOrders;
        newOrders = (NorthwindDataSet.OrdersDataTable)
            northwindDataSet.Orders.GetChanges(DataRowState.Added);
    
        if (newOrders != null)
        {
            try
            {
                ordersTableAdapter.Update(newOrders);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("AddNewOrders Failed");
            }
        }
    }
    

运行应用程序

F5 运行应用程序。