none
Rollback and Commit using entity framework RRS feed

  • Question

  • Hello

    I'm facing a problem with Entity Framework 4.0 and commit rollback

    For exemple

    I have a USER and an EMPLOYEE in DB the user has a Foreign Key from Employee property

    When I want to Add a new user I must add an employee before if not exist, I separate my application in differents layers:

    First the Data Access Layer with entity Framework

    Second the "Meta" Layer that deal internally with different services like update or register new objects

    Third my business layer where objects are totally differents from database representation and that expose WCF for client call

    When the client wants to add a new user he creates at the same time the new employee corresponding, in my "business service" I made two calls, one for the "employee meta service" which register a new employee and if it works fine, one to the "user meta service" which register the new user and use the employee Id as foreign key

    I've tested with a transaction scope but not works, i've tested passing the object context between the different services not works, and with each service his ObjectContext same result.

    What can I do if User not registered correctly, is there a way to rollback and not register the employee.

    it's a litlle complex to put some code here because there is a lot of classes...

    Thanks for read me



    • Edited by ange.fr Friday, July 13, 2012 9:42 AM
    Friday, July 13, 2012 9:39 AM

Answers

  •  I think you need to do SaveChanges() and remove the 'false' on both your
    contexts.
     
    Then you do a Scope.Complete()
     
    Yes the data is going to be saved to the database but not committed
    until the Scope.Complete() is done.
     
    You should do a divide by 0 on a line before the Scope.Complete() and
    blow the program up causing an exception.
     
    I think what you will see is the data is written to the database if you
    use SQL Server Management Studio while stopped at a breakpointsat at the
    divide by 0 statement. But it's not committed, and records will be
    rolled back when you execute the divide by 0 statement throwing the
    exception.
     
    • Proposed as answer by Alexander Sun Monday, July 16, 2012 8:25 AM
    • Marked as answer by ange.fr Tuesday, July 17, 2012 3:46 PM
    Friday, July 13, 2012 3:49 PM

All replies

  • On 7/13/2012 5:39 AM, ange.fr wrote:
    > Hello
    >
    > I'm facing a problem with Entity Framework 4.0 and commit rollback
    >
    > For exemple
    >
    > I have a USER and an EMPLOYEE in DB the user has a Foreign Key from
    > Employee property
    >
    > When I want to Add a new user I must add an employee before if not
    > exist, I separate my application in differents layers:
    >
    > First the Data Access Layer with entity Framework
    >
    > Second the "Meta" Layer that deal internally with different services
    > like update or register new objects
     
    Are you talking about the Service Layer?
    >
    > Third my business layer where objects are totally differents from
    > database representation and that expose WCF for client call
    >
    > When the client wants to add a new user he creates at the same time the
    > new employee corresponding, in my "business service" I made two calls,
    > one for the "employee meta service" which register a new employee and if
    > it works fine, one to the "user meta service" which register the new
    > user and use the employee Id as foreign key
    >
    > I've tested with a transaction scope but not works, i've tested passing
    > the object context between the different services not works, and with
    > each service his ObjectContext same result.
    >
    > What can I do if User not registered correctly, is there a way to
    > rollback and not register the employee.
    >
    > it's a litlle complex to put some code here because there is a lot of
    > classes...
    >
    > Thanks for read me
    >
    >
    >
     
    The transactions should be happening in the DAL. It's either it all
    makes it or none of it makes it. There should only be one context that
    should be established at the time the DAL is trying to persist objects
    through EF to the database.
     
    You should know in the DAL that User is a new object, and that an
    Employee object must be created for the User object, and the Employee
    object must be inserted into the database first to get the Emoloyee-ID
    and tie it to the User object.
     
    The whole thing should be happening in the DAL with transaction commit
    if everything is successful with the objects and persistence or
    everything is rolled back if any part is not successful.
     
     
    Friday, July 13, 2012 11:55 AM
  • I try to use only one context pass throught the different classes but if I do this when I call my first method "RegisterNewEmployee" and after the AddToEmployee and SaveChanges it register a new employee in database

    the context return to my WCF service and now go to my second method "RegisterNewUser" and after the AddToUser and SaveChanges it register a new User but an other Employee, it gaves me two new employees for one user.

    If I call only the AddToObject when my context back to the first service I don't retrieve my two objects.

    I'm not sure to be really clear...

    Friday, July 13, 2012 12:11 PM
  • On 7/13/2012 8:11 AM, ange.fr wrote:
    > I try to use only one context pass throught the different classes but if
     
    I have never done it. I don't see the purpose of doing it. All context
    and data persistence should be happening in the DAL for your scenario.
     DAL creates a context, goes into a transaction, persist the required
    objects, completes the transaction and desposes the context.
     
    > I do this when I call my first method "RegisterNewEmployee" and after
    > the AddToEmployee and SaveChanges it register a new employee in database
    >
    > the context return to my WCF service and now go to my second method
    > "RegisterNewUser" and after the AddToUser and SaveChanges it register a
    > new User but an other Employee, it gaves me two new employees for one user.
     
    You should have taken care of everything in the DAL in one-shot to avoid
    object duplication. You should be calling methods in the DAL back to
    back without leaving the DAL
    >
    > If I call only the AddToObject when my context back to the first service
    > I don't retrieve my two objects.
    >
    > I'm not sure to be really clear...
    >
     
    It's too complicated. You need to dumb it down.
     
    Where did you get this application architecture you are trying to
    implement?
     
    Friday, July 13, 2012 2:05 PM
  • I just test it on a very simply version and it seems working, will look at this for my solution

                EMPLOYEE newEmployee = new EMPLOYEE()
                {
                    FirstNameEmployee = "MyFirstName",
                    LastNameEmployee = "MyLastName"
                };
    
                USER newUser = new USER()
                {
                    RoleUser = "TestUser"
                };
    
                DirectCommitContainer contextEmployee = new DirectCommitContainer();
                DirectCommitContainer contextUser = new DirectCommitContainer();
    
                try
                {
                    using (TransactionScope scope = new TransactionScope())
                    {
                        contextEmployee.AddToEMPLOYEE(newEmployee);
                        contextEmployee.SaveChanges(false);
                        newUser.FKEmployee = contextEmployee.EMPLOYEE.FirstOrDefault(e => e.FirstNameEmployee == newEmployee.FirstNameEmployee && e.LastNameEmployee == newEmployee.LastNameEmployee).IdEmployee;
                        contextUser.AddToUSER(newUser);
    
                        contextUser.SaveChanges(false);
                        scope.Complete();
                        //contextEmployee.AcceptAllChanges();
                        //contextUser.AcceptAllChanges();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + ex.StackTrace);
                    Console.ReadLine();
                }

    If the user isertion fails the new employee was commited, I don't know yet the way I will take but sure I can use it

    Our architecture seems a little bit complicated to explain but it 's really easy to use, we have a lot of services and we want to decoupling from Database in case a client of us doesn't want SQL Server, we started developments two years ago and it's difficult to go back.

    A little schema is maybe more simple to understand

    first I call the Register employee and after I call the register user, if something fail I rollback

    Friday, July 13, 2012 2:40 PM
  •  I think you need to do SaveChanges() and remove the 'false' on both your
    contexts.
     
    Then you do a Scope.Complete()
     
    Yes the data is going to be saved to the database but not committed
    until the Scope.Complete() is done.
     
    You should do a divide by 0 on a line before the Scope.Complete() and
    blow the program up causing an exception.
     
    I think what you will see is the data is written to the database if you
    use SQL Server Management Studio while stopped at a breakpointsat at the
    divide by 0 statement. But it's not committed, and records will be
    rolled back when you execute the divide by 0 statement throwing the
    exception.
     
    • Proposed as answer by Alexander Sun Monday, July 16, 2012 8:25 AM
    • Marked as answer by ange.fr Tuesday, July 17, 2012 3:46 PM
    Friday, July 13, 2012 3:49 PM
  • That's exactly what I did on my precedent post and it works fine, I just have to use it on my solution which is more complex than my example

    thank  you Darnold

    Tuesday, July 17, 2012 3:46 PM