我在这里没有包含任何代码,因为我在过去几天里已经多次重写它真的不值得打扰,所以我会用通用术语来解释我的问题。
我有一个用C#编写的winforms应用程序并连接到sql server数据库。在我的应用程序的某些部分,我可以在数据库中的多个表上运行多达10个SQL命令,并且我需要在单个事务中包含它,因为它是“全有或全无”的情况。如果10个命令中的任何一个失败,我希望不提交任何命令。
复杂因素包括:
任何帮助都会受到最高的赞赏,因为我在这个问题的最后一周花费了大部分时间,感觉相对较少的进展。
编辑:
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。
答案 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)
答案 3 :(得分:0)
在您的情况下,使用命令模式是一个好习惯。实际上,它允许您撤消操作。事务很少适用于少数操作。但是有10个操作,最好在循环上执行每个命令,如果一个命令失败,则执行undo命令。这意味着您实现了回滚操作(此处为10)。 这里有一个模式样本的链接:http://www.dofactory.com/Patterns/PatternCommand.aspx