2012-07-28 70 views
0

我在这里没有包含任何代码,因为在过去的几天里我已经重写了很多次,真的不值得再打扰,所以我用通用术语解释我的问题。在单个ado.net事务中执行多个语句/ sqlco命令

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

复杂的因素包括:

  1. 每个10个sqlcommands的具有多个参数
  2. 一些sqlcommands的使用INSERT和我需要使用服务器生成的身份在一些后续的sqlcommands。
  3. 某些命令对相同数据进行操作,即早期命令可能会在数据库中插入一个新项目,而后面的一个sqlcommands将尝试更新该项目。

任何帮助将是最受赞赏,因为我在我的智慧结束这个问题花了大部分时间在这个问题上,而且感觉只有相对较小的进展。

编辑:

的sqlcommands原本在不同的班级等,但是我虽然是可能,所以我做了一个很大的重写是问题,现在所有的sqlcommands的是相同的方法中,尽管一些sqlcommands被写入其他地方并传递回主方法。

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

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

EDIT(一些代码)

这里只是在事务内的前两个sqlcommands:

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一样。

+0

10个命令是否在代码的不同位置。即不同的类,实例等? – devundef 2012-07-28 09:03:04

+0

究竟是什么,你有麻烦? – Andreas 2012-07-28 09:04:46

+0

真的不清楚你的问题究竟在哪里。为什么你不能使用'SqlTransaction'?也许可以尝试将它分解为更多的问题,每个问题都可以通过一个简单的*代码示例轻松地展现出* *特定的问题。 – 2012-07-28 09:18:00

回答

2

错误为这条线

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

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

0

您可以使用TransactionScope类。

here是很好的解释。

希望这有助于。

+0

不能在网络上使用MSDTC – PJW 2012-07-28 09:15:25

0

在你的情况下,使用命令模式是一种很好的做法。事实上,它可以让你撤销你的操作。对于少数操作,事务是有效的。但是对于10个操作,最好在循环中执行每个命令,并且如果一个命令失败,则使用undo命令。这意味着你实现了回滚操作(这里是10)。 这里有一个模式样本的链接:http://www.dofactory.com/Patterns/PatternCommand.aspx

1

不知道是否这是问题,但我没有看到你在哪里使用c.SetCaseNo在第二个SqlCommand上。

// 
    // 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(); 
+0

感谢您的支持 - 只发布了ExecuteNonQuery而不是ExecuteScalar的答案。 SetNewCase是CaseNo的第二个访问修饰符,绕过了我的类中内置的验证。 – PJW 2012-07-28 10:30:56