0

i am dealing with Entity framework 4 as the application is already been built and i have to make some up gradation in it.

Scenario: Implemented a DBTransaction(inserts data in database) in my code and once a transaction aborts in the mid way and roll back executes then on next time when same transaction executes with correct/validated data still the transaction abort by giving the previous exception. It is quite difficult to understand as i presume that the RollBack should remove the validation messages and data from the Database Context as it is SQL. Note: I am using a static DatabaseContext all through.

public class TestClass
{
    static SampleDataBaseEntities ctx = new SampleDataBaseEntities();

    public void SqlTransaction()
    {
        ctx.Connection.Open();
        using (DbTransaction transaction = ctx.Connection.BeginTransaction())
        {
            try
            {
                Student std = new Student();
                std.first_name = "first";
                //std.last_name = "last"; (This is responsible for generating the exception)
                AddTeacher();
                ctx.AcceptAllChanges();
                transaction.Commit();
            }
            catch (Exception e)
            {
                transaction.Rollback();
            }
            finally
            {
                ctx.Connection.Close();
            }
        }
    }

    public void SqlTransaction2()
    {
        ctx.Connection.Open();
        using (DbTransaction transaction = ctx.Connection.BeginTransaction())
        {
            try
            {
                Student std = new Student();
                std.first_name = "first";
                std.last_name = "last";
                AddTeacher();
                ctx.Students.AddObject(std);
                ctx.SaveChanges(false);
                transaction.Commit();
                ctx.AcceptAllChanges();
            }
            catch (Exception e)
            {
                transaction.Rollback();
                transaction.Dispose();
                ctx.Connection.Close();
            }
        }
    }

    public void AddTeacher()
    {
        Teacher t = new Teacher();
        t.first_name = "teacher_first";
        t.last_name = "teacher_last";
        t.school_name = "PUCIT";
        ctx.Teachers.AddObject(t);
        ctx.SaveChanges(false);
    }
}

class Program
{
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.SqlTransaction();
        test.SqlTransaction2();
    }
}

Solutions(Which i have tried): Using the SaveChanges(false). Using SaveChanges(false) and ctx.AcceptAllChanges().

Workaround: The workaround which i got is to re instantiate the DatabaseContext object.

As i have complexity issues while re instantiating the context that's why looking for a more appropriate solution. Thanks in advance.

  • Don't use a static DatabaseContext. Create one as you need it. Also your manual handling of the SQL transaction is not necessary. – Maarten Oct 13 '16 at 07:53
  • What are the 'complexity issues whlie re-instantiating the context' ? – Maarten Oct 13 '16 at 07:55
  • Don't use static DbContext as it is not designed to be thread safe. Also always use a `using` statement so that if anything goes wrong, the context will rollback any changes. – jegtugado Oct 13 '16 at 07:56
  • Create the context as late as possible and dispose it as soon as possible (use using!). Certainly not static. If you have 'complexity issues', first address these; then use the context in a correct way, as mentioned before by the others. – L-Four Oct 13 '16 at 07:57
  • Actually in application the context is been created in constructor and used through out the application. Is this the right way to use context objects? –  Oct 13 '16 at 09:15
  • Secondly, if i have to, how can i avoid to re instantiate context in my transaction scenario? –  Oct 13 '16 at 09:18
  • No, that is not the right approach. Create the context as late as possible and dispose it as soon as possible (use using!). You don't have to avoid to instantiate context; you have to instantiate context every time you need it. – L-Four Oct 13 '16 at 10:00
  • Thanks @L-Four. This certainly answers my first question. –  Oct 13 '16 at 10:57

2 Answers2

2

All problems come from not creating new instances of the context. Simplify your code to this and it should work.

using (var ctx = new SampleDataBaseEntities()) {
    Student std = new Student();
    std.first_name = "first";
    std.last_name = "last";
    ctx.Student.Add(std);
    ctx.SaveChanges();
}
Maarten
  • 22,527
  • 3
  • 47
  • 68
0

"The workaround which i got is to re instantiate the DatabaseContext object."

yes this is correct for doing the transaction again. Since you are using the static data context, so for the next time you do transaction the same data context is used that cause you problem re entering-data and validation errors.

Solution: Try never to use static dataContext since you are doing transactions very sooner. So you need updated datacontext for each transaction. so always try to instantiate a new dataContext and destroy it as soon as your transaction completes. Hope it will work!

CodeGenius
  • 514
  • 1
  • 6
  • 21
  • yeah! I got your point not to create a static object of context. Any how the issue is the context objects are initialized in the constructor and used all through the application. In Atomic Transaction scenario, when transaction aborts in mid way, the context objects keeps the exception. Next time when i try to use that context, it shows me the previous exception. Why does it so? –  Oct 13 '16 at 10:54
  • this is because you are again using "faulty" dataContext. – CodeGenius Oct 13 '16 at 10:57
  • If you need same object within same class, then why do you need to make it static? It will cause the problem because if you have created multiple objects of TestClass same dirty dataContext will be going to used. As DataContext should have minimum life time. – CodeGenius Oct 13 '16 at 11:00
  • you can also instantiate non-static DataContext in class that can be used throughout with the same object. – CodeGenius Oct 13 '16 at 11:01
  • I understand the purpose and advantage of DataContext re-instantiation. If i am not at liberty to re-instantiate, is there an any work around to refresh or clean the DbContext? –  Oct 13 '16 at 11:08
  • yes you can refresh your dataContext by using dataContext.Refresh method. Refer to the answer against this question: http://stackoverflow.com/a/18171125/3747199 – CodeGenius Oct 13 '16 at 11:12
  • Dangerous. When calling Refresh on a shared static datacontext, you might expect that other operations that run concurrently on that same context will fail. This will make your code unstable. I'm afraid your architecture is flawed. – L-Four Oct 13 '16 at 12:40
  • @Umar The `DbContext.Refresh` method does not clear the inner workings of the db-context. You need to have the objects that you want to refresh, and if you do not have those at that point, then you cannot 'refresh' the context. – Maarten Oct 13 '16 at 13:52