Rollback transaction to save point in case of failure ALTER TABLE ... ADD CONSTRAINT

Is there a way to add a control restriction in the transaction , and in the event of a rollback to a previous save point (rather than roll back the entire transaction)?

In my case, when the ALTER TABLE ... ADD CONSTRAINT command fails, the transaction cannot be returned to the save point (trying to do this throws an InvalidOperationException).

Review to demonstrate the decisive moment:

SqlTransaction transaction = connection.BeginTransaction();

// ... execute SQL commands on the transaction ...

// Create savepoint
transaction.Save("mySavepoint");

try
{
    // This will fail...
    SqlCommand boom = new SqlCommand(
        "ALTER TABLE table WITH CHECK ADD CONSTRAINT ...", 
        connection, 
        transaction);

    boom.ExecuteNonQuery();
}
catch
{
    // ...and should be rolled back to the savepoint, but can't.
    try
    {
        transaction.Rollback("mySavepoint");
    }
    catch (InvalidOperationException)
    {
        // Instead, an InvalidOperationException is thrown.
        // The transaction is unusable and can only be rolled back entirely.
        transaction.Rollback();
    }
}

And here is the demo code for testing ready to run (you need a data record with the name "test"):

public class Demo
{
    private const string _connectionString = "Data Source=(local);Integrated security=true;Initial Catalog=test;";
    private const string _savepoint = "save";
    private static readonly string _tableName = DateTime.Now.ToString("hhmmss");
    private static readonly string _constraintName = "CK" + DateTime.Now.ToString("hhmmss");

    private static readonly string _createTable = "CREATE TABLE [dbo].[" + _tableName + "] ([one] [int] NULL,[two] [int] NULL) ON [PRIMARY]";
    private static readonly string _insert1 = "INSERT INTO [" + _tableName + "] VALUES (1,1)";
    private static readonly string _addConstraint = "ALTER TABLE [dbo].[" + _tableName + "] WITH CHECK ADD  CONSTRAINT [" + _constraintName + "] CHECK (([one]>(1)))";
    private static readonly string _insert2 = "INSERT INTO [" + _tableName + "] VALUES (2,2)";


    public static void Main(string[] args)
    {
        // Example code! Please ignore missing using statements.

        SqlConnection connection = new SqlConnection(_connectionString);
        connection.Open();

        SqlTransaction transaction = connection.BeginTransaction();

        SqlCommand createTable = new SqlCommand(_createTable, connection, transaction);
        createTable.ExecuteNonQuery();

        // Create savepoint
        transaction.Save(_savepoint);

        SqlCommand insert1 = new SqlCommand(_insert1, connection, transaction);
        insert1.ExecuteNonQuery();

        try
        {
            // This will fail...
            SqlCommand boom = new SqlCommand(_addConstraint, connection, transaction);
            boom.ExecuteNonQuery();
        }
        catch
        {
            // ...and should be rolled back to the savepoint, but can't
            transaction.Rollback(_savepoint);
        }

        SqlCommand insert2 = new SqlCommand(_insert2, connection, transaction);
        insert2.ExecuteNonQuery();

        transaction.Commit();
        connection.Close();
    }
}
+5
source share
2 answers

, TSQL.

BEGIN TRAN

CREATE TABLE foo (col int)

INSERT INTO foo values (1)

SAVE TRANSACTION ProcedureSave;

BEGIN TRY
ALTER TABLE foo WITH CHECK ADD  CONSTRAINT ck CHECK (col= 2)
END TRY
BEGIN CATCH
    SELECT XACT_STATE() AS XACT_STATE
    /*Returns -1, transaction is uncommittable. Next line will fail*/

    ROLLBACK TRANSACTION ProcedureSave 
   /*Msg 3931, Level 16, State 1: The current transaction cannot be committed and
   cannot be rolled back to a savepoint. Roll back the entire transaction.*/
END CATCH

GO

SELECT @@TRANCOUNT AS [@@TRANCOUNT] /*Zero the transaction was rolled back*/

, , . , .

, . , . , . , . abort , - .

+1

, ​​ #. SQL:

BEGIN TRANSACTION

INSERT INTO Foos (Fooname)
VALUES ('Bar1')

SAVE TRANSACTION MySavePoint;

INSERT INTO Foos (FooName)
VALUES ('Bar2')

ROLLBACK TRANSACTION MySavePoint

COMMIT TRANSACTION

SQL :

using (SqlConnection conn = new SqlConnection("connectionString"))
{
    conn.Open();

    using (SqlTransaction trans = conn.BeginTransaction())
    using (SqlCommand comm = new SqlCommand("The Above SQL", conn, trans))
    {
        comm.ExecuteNonQuery();
        trans.Commit();
    }
}

trans.Rollback("MySavePoint");, , trans - .

SQL- :

using (SqlConnection conn = new SqlConnection("connectionString"))
        {
            conn.Open();

            using (SqlTransaction trans = conn.BeginTransaction())
            using (SqlCommand comm1 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar1')", conn, trans))
            using (SqlCommand comm2 = new SqlCommand("INSERT INTO Foos(fooName) VALUES('Bar2')", conn, trans))
            {
                comm1.ExecuteNonQuery();
                trans.Save("MySavePoint");
                comm2.ExecuteNonQuery();
                trans.Rollback("MySavePoint");
                trans.Commit();
            }
        }

, .

, , IDisposable - using.

:

http://www.davidhayden.com/blog/dave/archive/2005/10/15/2517.aspx

: , , - , SQL, . , , SQL - . - , , , , , .

0

All Articles