0

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

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

复杂的因素包括:

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

任何帮助都将不胜感激,因为我已经在这个问题上花费了一周的大部分时间,并且感觉进展相对较小。

编辑:

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

目前的问题是,第一个命令 (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...//

问题

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

4

4 回答 4

3

错误是这一行

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

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

于 2012-07-28T10:29:18.073 回答
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();   
于 2012-07-28T10:28:33.120 回答
0

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

于 2012-07-28T09:47:50.150 回答
0

您可以为此使用 TransactionScope 类。

是对它的很好的解释。

希望这可以帮助。

于 2012-07-28T09:10:05.590 回答