Skip to main content

Optimistic Concurrency

  • 4 minutes to read

Whenever you have multiple processes or threads that manipulate the same data, you run into concurrency problems. In general, there are three common ways to manage concurrency in a data store. These are: pessimistic concurrency, optimistic concurrency and “Last in wins”. eXpress Persistent Objects supports the last two.

With optimistic concurrency, locks are set and held only while a data store is being accessed. These locks prevent other users from updating objects at the same time. An object is unavailable to other sessions while its data is being updated. When an update is attempted, the original version of the changed object is compared against the existing object in the data store. If the two are different, the update fails with a concurrency error. In this instance, it is up to you to figure out how to reconcile the two objects using your business logic.

When creating a persistent object by deriving from the XPBaseObject, XPCustomObject or XPObject class, an OptimisticLockingAttribute is automatically applied. This attribute specifies whether a session can lock a persistent object’s state (allow optimistic locking to be enabled). To control object locking for objects that have the object locking option enabled, a new system field (OptimisticLockField) is added to the object table’s structure during the database schema update.

The primary purpose of Optimistic Locking is to prevent multiple clients from making modifications to the same object in a database. This is made possible by an optimistic locking field (called OptimisticLockField) that XPO adds to all persistent class tables, except for certain cases (see below). When objects are read from a database, an optimistic locking field is read together with the object content and stored for future use. When a modification is made to an object in a database, the optimistic locking field is checked and if it has been changed, XPO throws a LockingException. If everything is okay, the modification is written to the database and the OptimisticLockField is updated (by default, this field is of an integer type and its value is incremented).

try {
    unitOfWork.CommitChanges();
} catch (LockingException) {
    ShowMessage("One or more objects has been modified or deleted. You need to refresh data.");
}

If you derive a persistent class from the XPLiteObject class or use a session-less persistent class, the OptimisticLockingAttribute is not applied. In this instance, you should manually apply this attribute to enable optimistic locking.

[OptimisticLocking(true)]
public abstract class MyObject : XPLiteObject { 
    // ...
}

The locking of an object during a session is controlled by the session’s Session.LockingOption property. To enable optimistic locking for a specific session, assign LockingOption.Optimistic to this property.

session.LockingOption = LockingOption.Optimistic;

If this property is set to LockingOption.None, the original data is not checked and the persistent object is simply overwritten by an update (the last in wins rule). To enable field-level optimistic locking, use the Session.TrackPropertiesModifications property. To disable optimistic locking for a specific persistent property, apply the OptimisticLockingIgnoredAttribute to this property.

You can also specify how XPO behaves when it reloads changed objects (objects with different versions). Use the Session.OptimisticLockingReadBehavior property or OptimisticLockingReadBehaviorAttribute attribute for this purpose.

Member Table

Property, class Description
LockingException An exception thrown because an attempt is made to modify a row in a database, but its version doesn’t match the version of the row being posted.
Session.LockingOption Controls the persistent object’s locking during a session.
Session.OptimisticLockingReadBehavior Specifies how XPO behaves when reloading changed objects (objects with different versions).
OptimisticLockingAttribute Specifies that a persistent object’s state can be locked during a session.
See Also