views:

114

answers:

2

Let's assume we have a bunch of LINQ2SQL InsertOnSubmit statements against a given DataContext. If the SubmitChanges call is successful, is there any way to automatically generate a list of SQL commands (or even LINQ2SQL statements) that could undo everything that was submitted at a later time? It's like executing a rollback even though everything worked as expected.

Note: The destination database will either be Oracle or SQL Server, so if there is specific functionality for both databases that will achieve this, I'm happy to use that as well.

Clarification: I do not want the "rollback" to happen automatically as soon as the inserts have succesfully completed. I want to have the ability to "undo" the INSERT statements via DELETE (or some other means) up to 24 hours (for example) after the original program finished inserting data. We can ignore any possible referential integrity issues that may come up.

Assume a Table A with two columns: Id (autogenerated unique id) and Value (string)

If the LINQ2SQL code performs two inserts

 INSERT INTO Table A VALUES('a') // Creates new row with Id = 1
 INSERT INTO Table A VALUES('z') // Creates new row with Id = 2

<< time passes>>

At some point later I would want to be able "undo" this by executing

 DELETE FROM A Where Id = 1
 DELETE FROM A Where Id = 2

or something similar. I want to be able to generate the DELETE statements to match the INSERT ones. Or use some functionality that would let me capture a transaction and perform a rollback later.

We cannot just 'reset the database' to a certain point in time either as other changes not initiated by our program could have taken place since.

+2  A: 

It is actually quite easy to do this, because you can pass in a SqlConnection into the LINQ to SQL DataContext on construction. Just run this connection in a transaction and roll that transaction back as soon as you're done.

Here's an example:

string output;

using (var connection = new SqlConnection("your conn.string"))
{
    connection.Open();
    using (var transaction = connection.StartTransaction())
    {
        using (var context = new YourDataContext(connection))
        {
            // This next line is needed in .NET 3.5.
            context.Transaction = transaction;

            var writer = new StringWriter();
            context.Log = writer;

            // *** Do your stuff here ***

            context.SubmitChanges();

            output = writer.ToString();
        }

        transaction.Rollback();
    }
}
Steven
Sorry; I wasn't clear enough in the question. I don't want to rollback the transaction right away (necessarily). I want to have the SQL (or something) that I could run later in the future that would delete all the inserts that happened. (Let's assume we don't have to worry about referential integrity).
Jedidja
I updated my answer. Please look at the new code snippet.
Steven
That would generate the SQL to actually do the INSERTs :) I am looking to generate the code that would perform the DELETE statements.
Jedidja
I reread your question, but sorry; I have no idea.
Steven
I did learn something with your answer :) I hadn't realise you could log the statements executed with a DataContext so I appreciate your response regardless.
Jedidja
Your welcome :-)
Steven
A: 

Why do you need this?

Maybe you should explore the flashback possibilities of Oracle. It makes it possible to travel back in time.

It makes it possible to reset the content of a table or a database to how it once was at a specific moment in time (or at a specific system change number).

See: http://www.oracle.com/technology/deploy/availability/htdocs/Flashback_Overview.htm

TTT
I need this because even though a transfer between two systems may go exactly as planned, someone on one side may still want to be able to "undo" the migration afterwards. Probably within 24 hours.
Jedidja
We wouldn't want to reset the table/database to a specific moment in time as other operations may have happened since then. We would only want to delete our own inserts.
Jedidja
Can't you add an extra column to the table and fill it with some kind of "transfer job" number? If someone wants to "undo" a "transfer job" you simply delete all the rows with that specific job number.
TTT
Interesting idea; however we don't own the schema to the other database and there would be multiple tables involved. Something to consider, but the chances of approval for that seem slim.
Jedidja
I think it is the most simple solution and less error-prone. Adding new features often means that the schema has to change. Another solution is the use of a new set of tables for data that needs to be approved by "the other side". Once it is approved, you transfer this data to the production tables.
TTT