New Posts New Posts RSS Feed: ConcurrencyConflicts Learning Resources
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

ConcurrencyConflicts Learning Resources

 Post Reply Post Reply
Author
sebma View Drop Down
Groupie
Groupie
Avatar

Joined: 19-Aug-2008
Location: Singapore
Posts: 66
Post Options Post Options   Quote sebma Quote  Post ReplyReply Direct Link To This Post Topic: ConcurrencyConflicts Learning Resources
    Posted: 04-Mar-2010 at 7:30pm
Will inform my colleague, Viola, who caught this, not me ;-)

Thanks much.
Back to Top
IdeaBlade View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 30-May-2007
Location: United States
Posts: 353
Post Options Post Options   Quote IdeaBlade Quote  Post ReplyReply Direct Link To This Post Posted: 04-Mar-2010 at 6:42pm
Hey, good catch, Sebastian! Looks like that little critter has been in there for a while.

Each of the saves, including the one in step 3, does update the RowVersion value in the database. But when the save doesn't go through because of a concurrency conflict, and you then elect to force your local changes through, we make that possible by jury rigging the entity so it thinks it's not in conflict with the version in the database.

That we do with this call to RefetchEntity in method ResolveMyConflicts():

   pEntityManager.RefetchEntity(pEntityWithError, MergeStrategy.PreserveChangesUpdateOriginal);


The idea there is that we'll leave EntityVersion.Current for the entity as is (so your local changes remain in place), but update EntityVersion.Original to the same set of values that currently exist in the database for the entity in question. That way, when we resubmit the entity for saving, the concurrency engine won't see a conflict anymore (between the value of RowVersion that it finds in the database and the EntityVersion.Original value in the entity). 

The problem is that, because we're only updating the original values from the database, the current value for RowVersion is now actually 1 behind its value in the database. So when the save increments it by 1, it ends up being exactly equal to the value currently in the database. The save goes through, and the RowVersion value is updated in the database, but it is updated to the same value it had before. So then the next save doesn't realize the record got changed in the period since it was retrieved.

The fix is to include the following code right after the above-referenced call to RefetchEntity():

      // Set the Current values of the concurrency columns to what we just
      // got from the database in our call to RefetchEntity(). We want them to
      // enter the Save in the same state they would if we had retrieved the
      // entity from the database in the state it has there now and THEN made
      // our changes.
      EntityMetadata instanceMetadata = pEntityWithError.EntityAspect.EntityMetadata;
      foreach (DataEntityProperty property in instanceMetadata.ConcurrencyProperties) {
        property.SetValue(pEntityWithError,
          (pEntityWithError as BaseEntity).GetRawPropertyValue(
          property, EntityVersion.Original));
      }

Back to Top
sebma View Drop Down
Groupie
Groupie
Avatar

Joined: 19-Aug-2008
Location: Singapore
Posts: 66
Post Options Post Options   Quote sebma Quote  Post ReplyReply Direct Link To This Post Posted: 02-Mar-2010 at 10:16pm

Not sure if anyone encountered this from the Learning Resources Sample for ConcurrencyConflicts.

We found Concurrency Conflicts are not handled from the following issue steps:
 
0. Use sample code @..\IdeaBlade DevForce\Learning Resources\040_BusObjPersistence\ConcurrencyConflicts\Samples\300WNF_WinForms\CodeCS\UI\ConcurrencyHandler.cs
 
1. Call ResolveMyConflicts(...) to resolve conflicts
 
2. Modify a field (e.g. employee-> firstname) in app1, save, "Save Succeeded".

3. Update the same field in app2, save, a messagebox of the detailed conflicts will be shown, choose to save own copy, "Save Succeeded"

4. Then update the same field again in app1. No warning about conflicts, end up with "Save Succeeded" again.
 
Cause of problem: concurrency column(RowVersion) won't be updated by user2's SaveChanges()@step3. Which means @step4, app1 thinks its copy is the latest because of the RowVersion == the latest RowVersion in DB.

Is the above as designed?

Thanks
Sebastian
 
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down