views:

3919

answers:

4

I have a C#.net winform program which runs with a SQL Server database. I am using LINQ-to-SQL. Is it possible to rollback the call to one or more stored procedures inside a transaction within my program using LINQ-to-SQL?

Initially I thought it would make sense to manage the transaction inside the stored procedure but if I need to rollback more than one stored procedure call as part of a single transaction it would need to be done in my C# program.

Can someone point me to a code snippet on how to do this or provide some insight into an alternative?

A: 

Although I'm not using stored procs, you coudl have something like that:

    public Response<SomeObject> SaveSomething(Object yourObject)
    {
        DbTransaction dbTransaction = null;
        try
        {
            using (DataContext context = new DataContext())
            {
                    //Creates a new DB transaction
                    if (context.Connection.State == System.Data.ConnectionState.Closed)
                    {
                        context.Connection.Open();
                    }
                    dbTransaction = context.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable);
                    context.Transaction = dbTransaction;

   context.SaveYourObject(yourObject);
                    //Commit the transaction
                    dbTransaction.Commit();
                    response.ResponseObject = yourObject;
                    response.Messages.AddSuccessfulSave("Saved!");
                }
            }
        }
        catch (ChangeConflictException cex)
        {
            if (dbTransaction != null) dbTransaction.Rollback();
            response.Errors.AddConcurrencyError();
            response.IsSuccessful = false;
        }
        catch (SqlException sqlEx)
        {
            if (dbTransaction != null) dbTransaction.Rollback();
            if (sqlEx.Class == 14 && (sqlEx.Number == 2601 || sqlEx.Number == 2627)) //Duplicated key
            {
                response.Errors.Add(new Error
                {
                    Name = "Duplicate item",
                    Description = "This object already exists."
                });
                ExceptionPolicy.HandleException(sqlEx, SERVICE_EXCEPTION_POLICY);
                response.IsSuccessful = false;
            }
            else //other SQL errors
            {
                response.Errors.AddSavingError("Your object", yourObjectId);
                ExceptionPolicy.HandleException(sqlEx, SERVICE_EXCEPTION_POLICY);
                response.IsSuccessful = false;
            }
        }
afgallo
+12  A: 

Another alternative to DbTransaction is TransactionScope - this provides a much simpler programming model, and is extensible to multiple simultaneous databases and other feeds (via DTC) - but at the cost of a small amount of overhead on the connection. It used to be more overhead, but under SQL2005 etc it will use the "LTM" until you start spanning multiple connections - so a single operation is usually very cheap:

using (TransactionScope tran = new TransactionScope())
using (FooDataContext ctx = new FooDataContext())
{
    // your work with ctx
    // ...
    // other work involving connections etc
    // ...
    tran.Complete();
}

Very simple ;-p You should also be able to make the transaction more granular (over just a few queries) ormore encompassing very simply. Most existing code will automatically enlist in the transaction scope, making it very easy to retro-fit into existing code.

For more info on TransactionScope (and general transactions in .NET), see here.

Marc Gravell
just want to clarify one point if its not obvious : "The Complete method commits the transaction. If an exception has been thrown, complete is not called and the transaction is rolled back." (from first link above) So don't go looking for a 'rollback()' and don't have any code paths that do 'return' without Complete()
Simon_Weaver
A: 

i am getting exception when a system proc "sp_setapprole" (To authenticating user by sql server application role)executing in a transaction scope.

A: 

private string RollBack_fn() { int sal = 0; OracleConnection myconn = new OracleConnection(ConfigurationManager.AppSettings["con"].ToString()); cmd = new OracleCommand("SP_student_MAST", myconn); cmd.CommandType = CommandType.StoredProcedure; OracleParameter param1 = null, param2 = null, param3 = null, param4 = null, param5 = null;

    try
    {
        myconn.Open();
       trans = myconn.BeginTransaction();
        cmd.Transaction = trans;
        //param1 = new OracleParameter("pSNo", OracleType.VarChar, 5);
        //param1.Value ="";
        //cmd.Parameters.Add(param1);

        param2 = new OracleParameter("pSName", OracleType.VarChar, 10);
       // param2.Value = "Saravanan";
        param2.Value = TextBox1.Text;
        cmd.Parameters.Add(param2);

        param3 = new OracleParameter("pENo", OracleType.VarChar,5);
        param3.Value = TextBox2.Text;
        cmd.Parameters.Add(param3);

        param4 = new OracleParameter("pEName", OracleType.VarChar,10);
       // param4.Value = "Sangeetha";
        param4.Value = TextBox3.Text;
        cmd.Parameters.Add(param4);

        param5 = new OracleParameter("pSENo", OracleType.Char, 5);
        param5.Value = "";
        cmd.Parameters.Add(param5);
        sal = cmd.ExecuteNonQuery();
        trans.Commit();
        Response.Write("Record Saved");
        myconn.Close();
       // rollbackvalue = 0;
    }
    catch (Exception ex)
    {
        Response.Write("Not saved.RollBacked");
        trans.Rollback();
        //rollbackvalue = 1;
    }
    string cs = Convert.ToString(sal);
    return cs;

}