在单个ado.net事务中执行多个语句/ sqlcomands

时间:2012-07-28 09:00:45

标签: c# winforms ado.net transactions sqlcommand

我在这里没有包含任何代码,因为我在过去几天里已经多次重写它真的不值得打扰,所以我会用通用术语来解释我的问题。

我有一个用C#编写的winforms应用程序并连接到sql server数据库。在我的应用程序的某些部分,我可以在数据库中的多个表上运行多达10个SQL命令,并且我需要在单个事务中包含它,因为它是“全有或全无”的情况。如果10个命令中的任何一个失败,我希望不提交任何命令。

复杂因素包括:

  1. 10个sql命令中的每一个都有多个参数
  2. 某些sqlcommands使用INSERT,我需要在一些后续的sql命令中使用服务器生成的标识。
  3. 某些命令对相同的数据进行操作,即早期命令可能会在数据库中插入新项目,而后面的一个sql命令将尝试更新同一条目。
  4. 任何帮助都会受到最高的赞赏,因为我在这个问题的最后一周花费了大部分时间,感觉相对较少的进展。

    编辑:

    sqlcommands最初是在不同的类等中,但是我可能是问题,所以我做了一个大的重写,现在所有的sqlcommands都在同一个方法中,虽然有些sql命令是在别处编写的并且已经通过回到主要方法。

    目前的问题是,第一个命令(INSERT)被执行,但是第二个命令的事务失败,因为它试图引用第一个命令中创建的数据库条目。

    此外我无法使用TransactionScope,因为网络上的MSDTC会导致其他问题,所以我需要使用我的应用程序和ADO.NET来处理它。

    编辑(某些代码)

    以下是事务中的前两个sql命令:

    string connectionString = aSystem.ConnectionString;
    
        using (SqlConnection linkToDB = new SqlConnection(connectionString))
        {
            linkToDB.Open();
            using (SqlTransaction transaction = linkToDB.BeginTransaction())
            {
                try
                {                            
                    //...Case...//
    
                    cCase c = new cCase();
                    c.CaseType = cboCaseType.Text;
                    c.Occupation = txtOccupation.Text;
                    c.DateInstructed = txtDateInst.Text;
                    c.Status = "Live";
                    SqlCommand sqlSaveCase = c.SaveSqlCom();                               
                    sqlSaveCase.Connection = linkToDB;
                    sqlSaveCase.Transaction = transaction;
                    c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString();
    
                    //...IP Link...//
    
                    string strIPID = cboIPAddress.SelectedValue.ToString();
                    SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text);
                    sqlNewIPLink.Connection = linkToDB;
                    sqlNewIPLink.Transaction = transaction;
                    sqlNewIPLink.ExecuteNonQuery();                //...fails here...//
    
    
                    //...an additional 8 sql commands follow...//
    

    ISSUE

    sqlSaveCase命令在tblCases上插入一个新案例,但是当第二个命令sqlNewIPLink尝试使用第一个创建的Identity时,它会生成一个外键错误,就好像它没有从第一个命令中看到新创建的Case。

4 个答案:

答案 0 :(得分:2)

错误就是这一行

c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString(); 

应该使用ExecutreScalar()来从INSERT命令中检索ID。线索来了,当我最终意识到它总是返回1,我认为可能只是一个布尔'真'表示命令被执行。一旦我在命令上使用了ExecuteScalar,它就开始返回更有意义的ID,后续的SqlCommands确实识别了这些ID,因此没有Foregin Key问题。

答案 1 :(得分:1)

不确定这是不是问题,但我没看到你在第二个SqlCommand上使用c.SetCaseNo的位置。

  //
  // here you are setting c.SetCaseNo
  //
  c.SetCaseNo = sqlSaveCase.ExecuteNonQuery().ToString();

  string strIPID = cboIPAddress.SelectedValue.ToString();

  //
  // but here you're using c.CaseNo
  //
  SqlCommand sqlNewIPLink = cIPID.NewIPLinkSqlCom(strIPID,c.CaseNo,txtIPRef.Text);


  sqlNewIPLink.Connection = linkToDB;
  sqlNewIPLink.Transaction = transaction;
  sqlNewIPLink.ExecuteNonQuery();   

答案 2 :(得分:0)

您可以使用TransactionScope类。

here是对它的一个很好的解释。

希望这会有所帮助。

答案 3 :(得分:0)

在您的情况下,使用命令模式是一个好习惯。实际上,它允许您撤消操作。事务很少适用于少数操作。但是有10个操作,最好在循环上执行每个命令,如果一个命令失败,则执行undo命令。这意味着您实现了回滚操作(此处为10)。 这里有一个模式样本的链接:http://www.dofactory.com/Patterns/PatternCommand.aspx