This is a migrated thread and some comments may be shown as answers.

Commiting ObjectContainer transaction: two similar scenarios, different results

16 Answers 113 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Tomasz M.Lipiński
Top achievements
Rank 1
Tomasz M.Lipiński asked on 05 Jul 2010, 06:30 PM
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

16 Answers, 1 is accepted

Sort by
0
Jan Blessenohl
Telerik team
answered on 06 Jul 2010, 02:26 PM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 06 Jul 2010, 11:01 PM
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
0
Jan Blessenohl
Telerik team
answered on 08 Jul 2010, 04:27 PM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 09 Jul 2010, 09:40 PM

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

0
Jan Blessenohl
Telerik team
answered on 12 Jul 2010, 09:30 AM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 12 Jul 2010, 10:46 AM
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
0
Jan Blessenohl
Telerik team
answered on 12 Jul 2010, 11:10 AM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 12 Jul 2010, 11:19 AM
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
0
Jan Blessenohl
Telerik team
answered on 12 Jul 2010, 11:40 AM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 20 Jul 2010, 09:17 AM
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
0
Jan Blessenohl
Telerik team
answered on 20 Jul 2010, 03:30 PM
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
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 19 Oct 2010, 10:47 AM
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
0
Jan Blessenohl
Telerik team
answered on 19 Oct 2010, 01:15 PM
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
0
Adrian
Top achievements
Rank 2
answered on 10 Jun 2011, 05:07 PM
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.
0
Tomasz M.Lipiński
Top achievements
Rank 1
answered on 10 Jun 2011, 06:18 PM
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
0
PetarP
Telerik team
answered on 15 Jun 2011, 04:16 PM
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.
Tags
General Discussions
Asked by
Tomasz M.Lipiński
Top achievements
Rank 1
Answers by
Jan Blessenohl
Telerik team
Tomasz M.Lipiński
Top achievements
Rank 1
Adrian
Top achievements
Rank 2
PetarP
Telerik team
Share this question
or