简体   繁体   中英

Rollback changes when code not executed properly

I am new to SQL, In my project I am trying to fill the DataSet from the DataBase table and then inserting new rows in DataSet. After doing this, again I am filling the Database table with the DataSet data. Before filling I am clearing or deleting the Database table data. Well I achieved this by using the below code:

Database Table --> myTable
DataSet --> ds

OnButtonClick

   string strQuery = "delete from [dbo].[myTable]"
   SqlConnection conn = new SqlConnection(strConn);
   SqlCommand cmd = new SqlCommand(strQuery, conn);
   SqlCommand command;
   SqlDataAdapter da = new SqlDataAdapter(cmd);
   using (cmd)
   {
      using (conn)
      {
         conn.Open();
         cmd.ExecuteNonQuery();                    //deleting database table data
         foreach (DataRow dr in ds.Tables[0].Rows) //Inserting new data into the Database table
         {
             command = new SqlCommand(InsertQuery, conn);
             command.ExecuteNonQuery();
         }
         conn.Close();
      }
   }

The above code is working fine but when there is any exception in command sqlCommand then it is deleting the database table completely and not filling the DataSet. Any suggestions to modify this code? please help.

UPDATE:

            string strQuery = "delete from [dbo].[myTable]";
            using (SqlCommand cmd = new SqlCommand(strQuery, conn))
            {
                using (SqlCommand cmdReset = new SqlCommand("DBCC CHECKIDENT('myTable', RESEED, 0)", conn))
                {
                    SqlDataAdapter da = new SqlDataAdapter(cmd);
                    conn.Open();
                    SqlTransaction sqlTransaction = conn.BeginTransaction();
                    cmd.Transaction = sqlTransaction;
                    try
                    {
                        cmd.ExecuteNonQuery();                   //deleting database table data
                        cmdReset.ExecuteNonQuery();               //Resetting Identity of first column
                        foreach (DataRow dr in ds.Tables[0].Rows) //Inserting new data into the Database table
                        {
                            command = new SqlCommand(query.createDoctorRow(InsertQuery, conn);
                            command.ExecuteNonQuery();
                        }
                        sqlTransaction.Commit();
                        conn.Close();
                    }
                    catch (Exception e)
                    {
                        sqlTransaction.Rollback();
         /*ERROR*/      throw;  
                    }
                }
            }

ERROR --> "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized."

Use a transaction to run the sql

string strQuery = "delete from [dbo].[myTable]";

using (SqlConnection conn = new SqlConnection(strConn))
{
  using (cmd = new SqlCommand(strQuery, conn))
  {
     SqlDataAdapter da = new SqlDataAdapter(cmd);
     conn.Open();
     SqlTransaction sqlTransaction = conn.BeginTransaction();
     cmd.Transaction = sqlTransaction;
     try
     {
         cmd.ExecuteNonQuery();                    //deleting database table data
         foreach (DataRow dr in ds.Tables[0].Rows) //Inserting new data into the Database table
         {
             command = new SqlCommand(InsertQuery, conn);
             command.ExecuteNonQuery();
         }
         sqlTransaction.Commit();
         conn.Close();
     }
     catch(Exception e)
     {
         sqlTransaction.Rollback();
         throw;
     }
  }

}

Transactions form an all or nothing scenario. Either everything in the transaction works and is committed to the database, or the whole lot is cancelled as if nothing happened.

This example has a nice way of wrapping sql commands in a transaction scope. Basically if any exception is thrown during any of the row insert the delete query will fail as well.

In a nut shell you wrap everything inside a

 using (TransactionScope scope = new TransactionScope())
        {
            using (SqlConnection connection1 = new SqlConnection(connectString1))
            {
                 //enter your code here
            }
      }

Also you don't have to do an insert row by row you can use the SqlBulkCopy to do it more efficiently.

 using (SqlConnection connection =new SqlConnection(connectionString))
 {
        connection.Open();
        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
         {                               
                  bulkCopy.DestinationTableName = table.TableName;
                  bulkCopy.WriteToServer(table);
         }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM