Commiting ObjectContainer transaction: two similar scenarios, different results

17 posts, 0 answers
  1. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 05 Jul 2010 Link to this post

    Hi,
    Let's consider two scenarios.
    1. Scenario no. 1. In this scenario we have two lifecycles of the page:
    ObjectContainer cont = createObjectContainer(); // get a new container in some way  
    IObjectScope scope = globalScope;               // let's assume that this scope is stored somewhere in the Page  
    object theObject = getObject(scope, ..);        // get an object from the database  
    cont.CopyFrom(scope, "MyName", theObject, null);// copy this object to the container  
    Page.Session["MyContainer"] = cont;             // store the container in a session variable  
    // here goes some code that copies theObject to the Page's controls 
    This is the end of the first page's lifecycle. Then, the user changes data and presses "Save". The next lifecycle of the Page starts and:
                                                    // restore the container from the session variable  
    ObjectContainer cont = Page.Session["MyContainer"as ObjectContainer;  
    IObjectScope scope = globalScope;  
    scope.Transaction.Begin();  
    cont.Transaction.Begin();  
    object theObject = cont.NamedList("MyName")[0]; // restore the object from the container  
    // some code that updates theObject using client's data  
    cont.Transaction.Commit();                      // *** at this point the object in the database is unchanged yet  
    cont.CopyTo(scope, ObjectContainer.Verify.Changed);  
    scope.Transaction.Commit();                     // the changes go to the database  
    And it works very fine.

    2. Scenario no. 2.
    This scenario is nearly identical to the first one - with one exception: all this happens in a single lifecycle of the Page. In this case committing the container's transaction (the line marked with ***) saves changes to the database. This save, for some reasons, additionally changes some data in the database. And because of this, the following: cont.CopyTo(scope,....) fails (OptimisticVerificationFails).

    What should I do to be able to use this code in both scenarios?

    Regards
    Tomasz
  2. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 06 Jul 2010 Link to this post

    Hello Tomasz M.Lipiński,
    You should use ObjectContainer.CommitChanges. This returns an update script for your container that you can send back and Apply. Now the container has the real content from the DB and you can continue.


    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. DevCraft banner
  4. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 06 Jul 2010 Link to this post

    Hi,

    As I understand, you suggest something like this:
    ObjectContainer cont = Page.Session["MyContainer"as ObjectContainer;     
    IObjectScope scope = globalScope; 
    // there is no active scope's transaction now
    cont.Transaction.Begin();     
    object theObject = cont.NamedList("MyName")[0];  
    // ...  
    cont.Transaction.Commit();
    // below lines instead of cont.CopyTo and scope.Transaction.Commit
    ObjectContainer.ChangeSet chSet = 
        ObjectContainer.CommitChanges(cont.GetChanges(ObjectContainer.Verify.Changed),                                   
                                    ObjectContainer.Verify.Changed, scope, truetrue);  
    cont.Apply(chSet); 
    Is this true? If yes:
    In the first scenario it works - but CommitChanges begins and commits the scope's transaction. It's not good because I want to do some additional database updates in the same transaction (e.g. CommitChanges changes some object's data that should trigger modification of access rights to this object). In this case it is impossible - I must do it in a separate transaction.
    In my original scenario this part of the code is like this:
    cont.CopyTo(scope, ObjectContainer.Verify.Changed);  
    additionalSave(scope, ...);  //
    scope.Transaction.Commit(); 

    In the second scenario - problem remains exactly the same: cont.Transaction.Commit changes data in the database and CommitChanges fails with OptimisticVerificationFails.

    The main goal of the presented code is to implement the algorithm:
    - an object is presented in a preview mode
    - the user clicks Edit; this loads the object from the database again and stores it in a container (that is stored in a session variable); then the page is switched to the edit mode
    - the user enters some changes and clicks Save; this retrieves the object from the container, applies the changes and saves it to the database - being able to check whether the object hasn't been modified meantime.
    The second scenario is for implementing some functions that change the displayed object while in preview mode (e.g. a button "Change status to 'Approved'"). In this case I must check out this object, do changes and check it in - and the best way to do it is to use the existing methods of switching to the edit mode and saving the object to the database.

    Regards
    Tomasz
  5. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 08 Jul 2010 Link to this post

    Hello Tomasz M.Lipiński,
    Let me explain what the container know. To fulfill the optimistical concurrency control the container keeps stamps of all objects in the container. If you change the object in the database twice without refreshing the container stamps this will always lead to a CC exception. After the first commit the content of the container must be refreshed. This can be done by using CommitChanges and Apply or you can just call copyFrom again for all objects that you have in the container, or just start with a new container for the second cycle.


    Greetings,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  6. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 09 Jul 2010 Link to this post

    Hi,
    All you've written is OK and clear. But first of all, you haven't answered my questions. The first question is:
    Whether I've correctly understood your intention, whether the sequence of statements:

    • start the container's transaction
    • update my object inside the container
    • commit this transaction
    • commit changes to the scope
    • apply changes back to the container

    is correct?

    The next, more important question is:
    Why committing the container's transaction doesn't update the database in the first scenario (where creating and filling the container is done in one lifecycle of the page and updating the container and the database is done in another lifecycle) but DOES update the database in the second scenario, where all this is done during the same lifecycle?
    That is the core question.

    Regards
    Tomasz

  7. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 12 Jul 2010 Link to this post

    Hello Tomasz M.Lipiński,
    1. Yes.
    2. My guess is that you are changing the object twice once in the container, once in the scope. In the CopyTo we are now comparing if the original values of the object in the container are the same as the values of the object in the scope. If you did some changes to the object in the scope there is a conflict that we are reporting.

    Kind regards,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  8. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 12 Jul 2010 Link to this post

    Hi,

    I know perfectly what is the reason of the raised exeception (see my first post). But the question is not about it - the question is:
    Why commiting container's transaction in the first scenario doesn't save changes to the database but in the second scenario it DOES?

    My suspection is that in the first case the container is absolutely off-line (because all scopes that existed when it was created vanished at the end of the first lifecycle of the page) but in the second one knows this and that, tries to be a clever boy :-), finds the scope that contains the modified object and uses this scope to save data to the database.

    I'd like to repeat, that the only difference between the scenarios is that the first one is performed in two subsequent lifecycles of a web page and the second one is performed in a single lifecycle.

    I'm pretty sure that I must found some kind of workaround of this issue (e.g. not using (in the second scenario only) a container but using directly the scope) but I'd like to know not only what happens in my application but also - why.

    Regards
    Tomasz
  9. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 12 Jul 2010 Link to this post

    Hi Tomasz M.Lipiński,
    The container is always absolutely disconnected. The only difference I can see is that it is serialized in one case.

    I am a little confused now. You said that you see an OptimisticVerificationException that prevents the database update. Is the exception thrown in the CopyTo or the scope.Transaction.Commit? Which object is bound to the exception? The exceptions has a ConflictingObject method where you can find out which object has been changed. Did you change this object in the scope and in the container?

    Sincerely yours,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  10. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 12 Jul 2010 Link to this post

    Hi,

    The problem is not - why the exception is raised. It is raised because "container.Transaction.Commit()" saves data to the database and while saving the data are additionally modified by an update trigger.
    The problem is: why "container.Transaction.Commit()" saves data to the database? And why it once does it but another time - doesn't?

    Regards
    Tomasz
  11. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 12 Jul 2010 Link to this post

    Hi Tomasz M.Lipiński,
    The container.Transaction.Commit does never make a commit to the database, it sets only a flag on the container itself that you are allowed to call copyTo or CommitChanges. The changes are stored inside the db only if you call scope.Transaction.Commit or container.CommitChanges.

    Regards,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  12. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 20 Jul 2010 Link to this post

    Hi,
    OK, but I have seen database changing after container.Transaction.Commit().
    I must make a carefull review of my code and, maybe, prepare some simplified but complete example. But it will take some time.

    Regards
    Tomasz
  13. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 20 Jul 2010 Link to this post

    Hi Tomasz M.Lipiński,
    You should have access to the OpenAccess sources. If you set a breakpoint in OpenAccessPersistenceManagerImp.InternalCommit() you should get an idea when we are writing.

    Best wishes,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  14. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 19 Oct 2010 Link to this post

    Hi,
    well, I've got back to the problem after some break :-)
    You have written that "The container.Transaction.Commit does never make a commit to the database". But if it's the property DBConnection is filled and AutoSync is set to True - it does. And this is the point:
    - I've been using the ObjectContextProvider class and its GetNewObjectContainer method (OK, I agree that it's my fault; I guess it is designed not for this user case)
    - this method is setting these two properies as mentioned
    - when used in two lifecycles scenario - in the second one the db connection is lost, of course, and therefore commiting the container does not save data to the database
    - when used in a single lifecycle - the db connection is still active and AutoSync = True forces saving data to the database

    I've replaced GetNewObjectContainer method with a plain "new ObjectContainer()" and the single lifecycle scenario has started to work as expected.

    Regards
    Tomasz
  15. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 19 Oct 2010 Link to this post

    Hello Tomasz M.Lipiński,
    Ups, you are right, DBConnection and autosync are artifacts that are not well tested. The recommended way is to use the explicit API:
    ObjectContainer.CommitChanges()
    or
    container.CopyTo()

    This helps you also to see the exact places where the sync is done.

    Greetings,
    Jan Blessenohl
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  16. Adrian
    Adrian  avatar
    15 posts
    Member since:
    Dec 2010

    Posted 10 Jun 2011 Link to this post

    I have a database that works two operators and one operator delete an object, the second running in parallel oerator uses that object in another database without refresh before and the program crashes. How do I handle this error.
  17. Tomasz M.Lipiński
    Tomasz M.Lipiński avatar
    71 posts
    Member since:
    Nov 2009

    Posted 10 Jun 2011 Link to this post

    Hi,

    I think it's not the same topic and you should start a new thread.
    But this is the real problem and I'm also interested, how to solve it.

    Regards
    Tomasz
  18. PetarP
    Admin
    PetarP avatar
    754 posts

    Posted 15 Jun 2011 Link to this post

    Hello Tomasz M.Lipiński,

     Please have a look in your other thread located here. I suggest we continue the discussion there as this thread is not really related to the question itself.

    Greetings,
    Petar
    the Telerik team
    Q1’11 SP1 of Telerik OpenAccess is available for download; also available is the Q2'11 Roadmap for Telerik OpenAccess ORM.
Back to Top
DevCraft banner