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

C# 在单个ado.net事务中执行多个语句/sqlcomands,c#,winforms,ado.net,transactions,sqlcommand,C#,Winforms,Ado.net,Transactions,Sqlcommand,我这里不包括任何代码,因为在过去几天里我已经写了很多次了,实在不值得再费心了,所以我将用一般术语解释我的问题 我有一个用C#编写的winforms应用程序,并连接到sql server数据库。在我的应用程序的某些部分中,我可以在数据库中的许多表上运行多达10个SQL命令,并且我需要在单个事务中包含这些SQL命令,因为这是一种“要么全有,要么全无”的情况。如果10个命令中的任何一个失败,我希望不提交任何一个命令 复杂因素包括: 10个SQLCommand中的每一个都有多个参数 一些sqlcomma

我这里不包括任何代码,因为在过去几天里我已经写了很多次了,实在不值得再费心了,所以我将用一般术语解释我的问题

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

复杂因素包括:

  • 10个SQLCommand中的每一个都有多个参数
  • 一些sqlcommands使用INSERT,我需要在一些后续sqlcommands中使用服务器生成的标识
  • 某些命令对相同的数据进行操作,即早期的命令可能会在数据库中插入一个新项,随后的一个sqlcommands将尝试更新相同的条目
  • 任何帮助都将不胜感激,因为我对这个问题束手无策,花了一周的时间在这个问题上,感觉进展相对较小

    编辑:

    sqlcommands最初是在不同的类中等,但是我认为这可能是问题所在,所以我做了一个大的重写,现在所有的sqlcommands都在同一个方法中,尽管有些sqlcommands是在其他地方编写的,并传递回主方法

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

    此外,我不能使用TransactionScope,因为网络上的MSDTC会导致其他问题,因此我需要使用我的应用程序和ADO.NET处理此问题

    编辑(一些代码)

    以下是事务中的前两个SQLCommand:

    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...//
    
    发行


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

    您可以使用TransactionScope类

    这是很好的解释


    希望这对您有所帮助。

    您可以使用TransactionScope类

    这是很好的解释


    希望这能有所帮助。

    在您的情况下,使用命令模式是一种很好的做法。事实上,它允许您撤消操作。事务只适用于少数操作。但对于10个操作,最好在循环中执行每个命令,如果一个命令失败,则执行undo命令。这意味着您要实现回滚操作(这里是10)。
    这里有一个与模式示例的链接:http://www.dofactory.com/Patterns/PatternCommand.aspx

    在您的案例中,使用命令模式是一个很好的实践。事实上,它允许您撤消操作。事务只适用于少数操作。但对于10个操作,最好在循环中执行每个命令,如果一个命令失败,则执行undo命令。这意味着您要实现回滚操作(这里是10)。
    这里有一个与模式示例的链接:http://www.dofactory.com/Patterns/PatternCommand.aspx不确定这是否是问题所在,但我看不出在第二个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();   
    

    不确定这是否是问题所在,但我不知道在第二个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();   
    

    错误就在这一行

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

    应该使用ExecutreScalar()从INSERT命令检索ID。当我最终意识到它总是返回1时,我想这可能只是一个布尔值“true”,表示命令已执行。我在命令上使用ExecuteScalar后,它开始返回更多有意义的ID,后续SqlCommands无法识别这些ID,因此没有Foregin键问题。

    错误是这一行

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

    应该使用ExecutreScalar()从INSERT命令检索ID。当我最终意识到它总是返回1时,我想这可能只是一个布尔值“true”,表示命令已执行。一旦我在命令上使用了ExecuteScalar,它就开始返回更有意义的ID,后续的SqlCommands没有识别这些ID,因此没有Foregin关键问题。

    是代码中不同位置的10个命令。i、 不同的类、实例等?你到底有什么问题?你到底有什么问题还不清楚。为什么不能使用
    SqlTransaction
    ?也许可以试着把这个问题分成更多的问题,每个问题处理一个可以通过简单的代码示例轻松演示的特定问题。您的示例代码实际上是有效的(尽管您似乎有设计问题)。什么东西不起作用?sqlSaveCase命令在tblCases上插入一个新的案例,但当第二个命令sqlNewIPLink尝试使用第一个命令创建的标识时,它会生成一个外键错误,好像它没有从第一个命令中看到新创建的案例。这10个命令在代码中的不同位置。i、 不同的类、实例等?你到底有什么问题?你到底有什么问题还不清楚。为什么不能使用
    SqlTransaction
    ?也许可以试着把这个问题分成更多的问题,每个问题处理一个可以通过简单的代码示例轻松演示的特定问题。您的示例代码实际上是有效的(尽管您似乎有设计问题)。什么是不起作用的?sqlSaveCase命令在tblCases上插入一个新的案例,但是当第二个命令sqlNewIPLink尝试使用第一个命令创建的标识时,它会生成一个外键错误,就好像它没有从第一个命令中看到新创建的案例一样。谢谢-刚刚发布了答案