如何在foreach循环中插入列表时处理事务

时间:2014-05-30 17:53:35

标签: c# sql .net rollback

我在DAL中有这个方法,它将列表中的所有对象插入到foreach循环中的表中。但问题是如何处理事务,如果无法插入列表中的任何项目,则应回滚整个过程。有办法解决这个问题,还是我必须改变方法?

public bool InsertEarnings(List<Earning> earningsList)
{
    using (SqlConnection sqlConnection = new SqlConnection(db.GetConnectionString))
    {
        string insertStatement = "IF NOT EXISTS (SELECT * FROM SalaryTrans WHERE employee_id=@employee_id) " +
        "BEGIN INSERT INTO salaryTrans... " + 
        "ELSE BEGIN UPDATE SalaryTrans SET" ;

        using (SqlCommand sqlCommand = new SqlCommand(insertStatement, sqlConnection))
        {
            SqlParameter paramEmployeeID = new SqlParameter("@employee_id", SqlDbType.Char);
            SqlParameter paramWorDays = new SqlParameter("@work_days", SqlDbType.Int);
            //


            sqlCommand.Parameters.Add(paramEmployeeID);
            sqlCommand.Parameters.Add(paramWorDays);
            //

            sqlConnection.Open();                    

            foreach (Earning earning in earningsList)
            {
                paramEmployeeID.Value = earning.EmployeeID;
                paramWorDays.Value = earning.WorkDays;
                //

                sqlCommand.ExecuteNonQuery();
            }
            return true;
        }
    }
}

4 个答案:

答案 0 :(得分:3)

查看此示例,在表中coches所有字段nvarchar(50) IdCoche是PrimaryKey,表是空的

  private void button1_Click(object sender, EventArgs e)
    {
        //Reading conection from App Settings
        //this insert values from 20 to 29
        ExecuteSqlTransaction(Settings.Default.Conexion,20);
        //this must insert values from 15 to 24
        //But at 20 a PrimaryKey infraction raise exception and rollback
        ExecuteSqlTransaction(Settings.Default.Conexion, 15);

    }
private static void ExecuteSqlTransaction(string connectionString,int start)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;
        transaction = connection.BeginTransaction("SampleTransaction");
        // Must assign both transaction object and connection 
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;
        command.CommandText = "INSERT INTO [dbo].[Coches] ([IdCoche],[Marca],[Modelo],[Version]) VALUES (@IdCoche,@Marca,@Modelo,@Version)";
        command.Parameters.AddRange(new SqlParameter[]{
                new SqlParameter("@IdCoche",""),
                new SqlParameter("@Marca",""),
                new SqlParameter("@Modelo",""),
                new SqlParameter("@Version","")
            });
        try
        {
            for (int i = start; i < start + 10; i++)
            {
                command.Parameters["@IdCoche"].Value = "IdCoche"+i.ToString();
                command.Parameters["@Marca"].Value = "Marca" + i.ToString(); ;
                command.Parameters["@Modelo"].Value = "Modelo" + i.ToString(); ;
                command.Parameters["@Version"].Value = "Version" + i.ToString(); ;
                command.ExecuteNonQuery();
            }

            // Attempt to commit the transaction.
            transaction.Commit();
            Console.WriteLine("10 records are written to database.");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
            Console.WriteLine("  Message: {0}", ex.Message);

            // Attempt to roll back the transaction. 
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex2)
            {
                // This catch block will handle any errors that may have occurred 
                // on the server that would cause the rollback to fail, such as 
                // a closed connection.
                Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
                Console.WriteLine("  Message: {0}", ex2.Message);
            }
        }
    }
}

答案 1 :(得分:1)

您正在做的事情效率非常低,因为您正在为&#34; if&#34 ;.

进行查询。

如果每个员工只能拥有一条记录,那么字段employee_id应该是唯一的,如果你用&#34; INSERT INTO ...替换你的查询,请重复更新...&#34 ;将会更快(取决于您的记录计数),如果无法插入行,则不会中断。

答案 2 :(得分:1)

In This link他们描述的东西看起来就像你想要做的那样。他建议使用SqlCommand,而不是使用SqlTransaction,您可以运行您的插入内容,如果一切成功,则使用transaction.Commit其他transaction.Rollback

希望有所帮助

答案 3 :(得分:1)

如果您使用从C#代码启动的事务,它将启动具有大量开销的MSDTC,如果可能应该避免。如果有机会,请使用带有table parameter的存储过程,使用SQL命令构建并提交表,并在数据库中执行事务控制,而不是使用分布式事务协调器会话。我还建议使用MERGE语法。