65.9K
CodeProject 正在变化。 阅读更多。
Home

C#: 避免使用类型化数据集和 SQL Server 2000 的 DTC

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.82/5 (5投票s)

2006年11月16日

CPOL

2分钟阅读

viewsIcon

62836

一篇文章,描述了一种为使用数据集向导设计的应用程序提供事务支持的简单方法,并避免使用 TransactionScope 和 SQL Server 2000 的 DTC 要求。

引言

本文描述了一种在 C# 2.0 和 SQL Server 2000 中为类型化数据集启用事务支持的方法,而无需使用 System.Transactions.TransactionScope,从而避免分布式事务协调。

背景

我为一位客户创建了一个应用程序,需要将数据从电子表格导入到我们的 SQL Server 2000 数据库中。我希望在事务中执行此操作,但发现唯一的方法似乎是使用 TransactionScope,这将需要 DTC 存在,并会使用比必要更多的资源。我需要一种简单的方法来增强 Visual Studio 2005 DataSet 编辑器生成的 DataSet 代码,以便我可以将生成的数据适配器列入事务。

我发现由于生成的适配器继承 System.ComponentModel.Component 而不是 DataAdapter,因此我无法访问 UpdteCommandInsertCommandDeleteCommand,从而无法设置每个事务属性。我需要找到另一种方法。

代码中的问题

你根本无法这样做

using (SqlTransaction transaction = connection.BeginTransaction())
{
    // The following won’t compile because adapter1 and adapter2 
    // inherit from System.ComponentModel.Component, not DataAdapter
    adapter1.UpdateCommand.Transaction = transaction;
    adapter2.UpdateCommand.Transaction = transaction;
    // Also set transaction on insert and delete commands here

    adapter1.Update(table1);
    adapter2.Update(table2);

    transaction.Commit();
}

我可以使用 System.Transactions,这会使事情变得简单得多

using (TransactionScope transaction = new TransactionScope())
{
    adapter1.Update(table1);
    adapter2.Update(table2);

    transaction.Complete();
}

但是,由于我们使用的是 SQL Server 2000,它将自动提升为分布式事务,需要服务器上运行分布式事务协调器服务,并在此过程中使用更多的资源。SQL Server 2005 支持确定事务是否应提升为分布式事务,因此在使用 2005 时,System.Transactions.TransactionScope 可能是更好的选择,因为它更简单,并且没有额外的开销。

代码中的解决方案

我找不到除 System.Transactions 之外的文档化的方法来解决此问题,因此我通过扩展 VS 生成的数据集来解决,以便为我希望进行事务控制的每个适配器添加一个 EnlistTransaction 方法。这只是为 Command 对象添加一个后门。我基本上将生成的 DataSet 变成了一个部分类,并在新创建的文件中添加了新方法,以便通过添加列等方式进行重新生成不会破坏它。

我的第一个示例现在变成

using (SqlTransaction transaction = connection.BeginTransaction())
{
       // These methods will update all relevant command objects’ transaction property
       adapter1.EnlistTransaction(transaction);
       adapter2.EnlistTransaction(transaction);
 
       adapter1.Update(table1);
       adapter2.Update(table2);
 
       transaction.Commit();
}

关注点

以下是修改生成的 dataset 的实际步骤。诀窍是将其变成一个部分类,如下所示

  1. 在解决方案资源管理器中选择你的 dataset,然后单击 查看代码。这将自动创建额外的代码文件。
  2. 为希望提供事务支持的 dataadapter 创建部分类。
  3. 添加以下代码(根据需要替换名称)
    public partial class [TableAdapterName]
    {
        public void EnlistTransaction(System.Data.SqlClient.SqlTransaction transaction)
        {
            System.Data.SqlClient.SqlTransaction _transaction;
            
            if (this._transaction != null)
            {
                throw new System.InvalidOperationException
    		("This adapter has already been enlisted in a transaction");
            }
            else
            {
                this._transaction = transaction;
                Adapter.UpdateCommand.Transaction = _transaction;
                Adapter.InsertCommand.Transaction = _transaction;
                Adapter.DeleteCommand.Transaction = _transaction;
            }
        }
    }

现在你已经准备好了!

历史

  • 2006 年 11 月 16 日:初始发布
© . All rights reserved.