我正在使用VS.net和SQL Server开发一个小型桌面应用程序。
我在代码中使用SqlTransaction
:
SqlTransaction tran = null;
SqlCommand cmd = new SqlCommand();
int lstInsSubjId = -1;
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
tran = con.BeginTransaction("Transaction1");//Transaction begin
tran.Save("Savepoint_1");//Savepoint 1
string sql1 = @"insSubject";
cmd = new SqlCommand(sql1, con, tran);
cmd.Parameters.Add("@lstInsSubjId", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("@sub_name", SqlDbType.VarChar).Value = txtSubjectName.Text.Trim();
cmd.CommandType = CommandType.StoredProcedure;
tran.Save("Savepoint_2");//Savepoint 2
cmd.ExecuteNonQuery();
lstInsSubjId = Convert.ToInt32(cmd.Parameters["@lstInsSubjId"].Value);
for (int i = 0; i < clbClasses.CheckedItems.Count; i++)
{
int clsId = Convert.ToInt32(((DataRowView)clbClasses.CheckedItems[i]).Row["c_id"].ToString());
cmd.CommandText = @"INSERT INTO tblClassSubjectMap_mavis(c_id, sub_id)
VALUES(@c_id, @sub_id)";
cmd.Parameters.Add("@c_id", SqlDbType.Int).Value = clsId;
cmd.Parameters.Add("@sub_id", SqlDbType.Int).Value = lstInsSubjId;
cmd.CommandType = CommandType.Text;
//tran.Save("Savepoint_3");//Savepoint 3
cmd.ExecuteNonQuery();
}
tran.Commit();//Transaction commit
MessageBox.Show("Records added", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
txtSubjectName.Text = "";
txtSubjectName.Focus();
frmSubjectBrows.subList.bindListView();
}
}
catch (SqlException ex)
{
if (tran != null)
{
tran.Rollback();
MessageBox.Show(ex.Message.ToString() + "\nTransaction Rolledback", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
在代码的结尾处,在for循环中,如果有多个检查项,即,如果它多次迭代/循环,则将引发错误,并且从不提交事务。但是,如果仅循环一次,则没有错误,事务将提交。
错误消息是:
在System.Data.dll中发生了类型为'System.InvalidOperationException'的未处理异常
其他信息:此SqlTransaction已完成;它不再可用。
在Internet上寻找答案时,一些解决方案指出,如果在提交之前突然关闭了事务,则可能会发生这种错误。但是我不明白交易在这里如何完成。
谁能告诉我出了什么问题?预先感谢。
答案 0 :(得分:1)
为每个命令使用sqlcommand的新实例,请参见
上的示例
https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqltransaction?view=netframework-4.8
尝试此代码:
int lstInsSubjId = -1;
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand cmd = connection.CreateCommand();
SqlTransaction tran = con.BeginTransaction("Transaction1");//Transaction begin
cmd.Connection = cmd;
cmd.Transaction = tran;
tran.Save("Savepoint_1");//Savepoint 1
cmd.CommandText = @"insSubject";
cmd.Parameters.Add("@lstInsSubjId", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("@sub_name", SqlDbType.VarChar).Value = txtSubjectName.Text.Trim();
cmd.CommandType = CommandType.StoredProcedure;
tran.Save("Savepoint_2");//Savepoint 2
cmd.ExecuteNonQuery();
lstInsSubjId = Convert.ToInt32(cmd.Parameters["@lstInsSubjId"].Value);
for (int i = 0; i < clbClasses.CheckedItems.Count; i++)
{
int clsId = Convert.ToInt32(((DataRowView)clbClasses.CheckedItems[i]).Row["c_id"].ToString());
SqlCommand cmd2 = connection.CreateCommand();
cmd2.Connection = cmd2;
cmd2.Transaction = tran;
cmd2.CommandText = @"INSERT INTO tblClassSubjectMap_mavis(c_id, sub_id)
VALUES(@c_id, @sub_id)";
cmd2.Parameters.Add("@c_id", SqlDbType.Int).Value = clsId;
cmd2.Parameters.Add("@sub_id", SqlDbType.Int).Value = lstInsSubjId;
cmd2.CommandType = CommandType.Text;
//tran.Save("Savepoint_3");//Savepoint 3
cmd2.ExecuteNonQuery();
}
tran.Commit();//Transaction commit