Skip to main content
All docs
V25.1
  • .NET 8.0+

    Optimistic Locking (Concurrency Control in EF Core)

    • 5 minutes to read

    XAF uses the optimistic concurrency control (OCC) mechanism to handle data conflicts.

    Objects with optimistic locking contain a concurrency token field that updates with each change in the database. XAF compares the local token value with the database value when changes are submitted. If they match, local changes overwrite database values and XAF updates the token. If they differ, XAF merges changes automatically or offers conflict resolution options based on configuration settings.

    To support optimistic locking, a business class must implement the IOptimisticLock interface.

    Tip

    This topic contains code samples based on the MainDemo Blazor Server demo application that ships with XAF. You can find this demo in the following folder: %PUBLIC%\Documents\DevExpress Demos 25.1\Components\XAF\MainDemo.NET.EFCore\CS\MainDemo.Blazor.Server.

    Enable Optimistic Locking

    Optimistic locking is available in new XAF applications out of the box for the BaseObject class and all its descendants.

    In case of concurrent changes, XAF merges non-conflicting changes and displays a pop-up window with resolution options for conflicting changes.

    To enable optimistic locking in an existing application, add the following code to the DbContext.OnModelCreating() method:

    using DevExpress.Persistent.BaseImpl.EF;
    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Module.BusinessObjects;
    
    public class MainDemoDbContext : DbContext {
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            //...
            modelBuilder.UseOptimisticLock()
        }
    }
    

    Configure Concurrency Options

    Optimistic locking functionality offers two options to fine-tune conflict detection and resolution in your system:

    OptimisticLockDetection
    Specifies whether XAF identifies conflicting changes using the object’s concurrency token or by assessing all object properties.
    OptimisticLockHandling
    Defines how XAF handles conflicts: automatic merging or conflict resolution options.

    You can specify both options for an object space in the application builder. These settings will affect your entire application.

    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Blazor.Server;
    
    public class Startup {
        //...
        public void ConfigureServices(IServiceCollection services) {
            //...
            services.AddXaf(Configuration, builder => {
                builder.UseApplication<MainDemoBlazorApplication>();
                //...
                builder.ObjectSpaceProviders
                    .AddSecuredEFCore(o => { o.PreFetchReferenceProperties();
                        o.OptimisticLockHandling = DevExpress.ExpressApp.DC.OptimisticLockHandling.Reload;
                        o.OptimisticLockDetection = DevExpress.ExpressApp.DC.OptimisticLockDetection.AllFields;
                    })
            })
        }
    }
    

    To specify custom behavior for a specific class, use the OptimisticLock attribute:

    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Module.BusinessObjects;
    
    [OptimisticLock(OptimisticLockDetection = OptimisticLockDetection.AllFields,OptimisticLockHandling = OptimisticLockHandling.Reload)]
    public class Department : BaseObject, ITreeNode {
        //...
    }
    

    Resolve Collisions Behavior

    XAF offers a variety of conflict resolution strategies that depend on the combination of OptimisticLockHandling and OptimisticLockDetection values.

    If you specify Default for OptimisticLockHandling or OptimisticLockDetection option, XAF disables conflict resolution and displays a warning message. When you refresh data, the database version overwrites local changes.

    The following table covers other available combinations of the OptimisticLockDetection and OptimisticLockHanding options and describes XAF behavior when concurrency changes are detected:

    OptimisticLockHandling OptimisticLockDetection = OptimisticLockField OptimisticLockDetection = AllFields
    None XAF displays a pop-up window with resolution options. If changes do not conflict, XAF displays a pop-up window with merge options. If changes are conflicting, XAF displays a pop-up window with resolution options.
    Merge If XAF detects changes, it displays a pop-up window with resolution options. If changes do not conflict, XAF merges the changes in the background. If changes are conflicting, XAF displays a pop-up window with resolution options.
    Ignore XAF overwrites the database object with the local version. XAF merges non-conflicting changes and overwrites conflicting database changes with the local values.
    Reload XAF overwrites the local object with the database version. XAF merges non-conflicting changes and overwrites conflicting local changes with the database values.

    If a user modifies an object that was deleted from the database, XAF shows a warning message and deletes the local version.

    Resolve Collision Dialog

    XAF ASP.NET Core Blazor Collision Handling Pop-Up Window, DevExpress|

    XAF displays this pop-up window when it detects concurrency conflicting changes in an object and the resulting conflicts cannot be resolved automatically.

    Apply My Changes
    XAF applies the local version of conflicting changes and the database version of non-conflicting changes.
    Apply Their Changes
    XAF takes the database version of conflicting changes and the local version of non-conflicting changes.
    Discard All My Changes
    XAF overwrites all local changes with the database version.
    Cancel
    XAF cancels the “Save” operation.

    Merge Dialog

    XAF ASP.NET Core Blazor Conflict Resolution Pop-Up Window, DevExpress|

    XAF displays this pop-up window when it detects concurrency non-conflicting changes in an object (for the combination of OptimisticLockDetection.AllFields and OptimisticLockHandling.None options).

    Merge
    XAF merges changes.
    Discard All My Changes
    XAF overwrites all local changes with the database version.
    Cancel
    XAF cancels the “Save” operation.

    Conflict Warning Message

    XAF ASP.NET Core Blazor Warning, DevExpress

    XAF displays this warning when:

    • Conflict resolution is disabled.
    • When a user attempts to modify a deleted object.
    • When a user attempts to delete a modified object.

    Customize Collision Behavior Dynamically at Runtime

    XAF includes a ProcessDataLockingInfoController. Use this controller to implement your own collision handling strategies. Handle the DataLockingProcessing event to manage information about modified records and collisions.

    The following code snippet enables automatic merge in XAF applications:

    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.SystemModule;
    
    namespace MainDemo.Module.Controllers;
    
    public class AutoMergeViewController : ViewController {
        private ProcessDataLockingInfoController lockController;
    
        private void OnDataLocking(object sender, DataLockingProcessingEventArgs e) {
            foreach (var info in e.DataLockingInfo.ObjectLockingInfo) {
                info.CanAutoMerge = info.CanMerge;
            }
        }
    
        protected override void OnActivated() {
            base.OnActivated();
            lockController = Frame.GetController<ProcessDataLockingInfoController>();
            lockController.DataLockingProcessing += OnDataLocking;
        }
    
        protected override void OnDeactivated() {
            base.OnDeactivated();
            if (lockController != null) {
                lockController.DataLockingProcessing -= OnDataLocking;
                lockController = null;
            }
        }
    }
    

    Disable Optimistic Locking For an Entire Application

    To disable optimistic locking in an entire application, remove modelBuilder.UseOptimisticLock(); from the DbContext.OnModelCreating() method:

    using DevExpress.Persistent.BaseImpl.EF;
    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Module.BusinessObjects;
    
    public class MainDemoDbContext : DbContext {
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            //...
            modelBuilder.UseOptimisticLock();
    
            //...
        }
    }
    

    Disable Optimistic Locking For a Specific Class

    To disable optimistic locking for a specific class, add the OptimisticLockIgnore attribute to the class declaration:

    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Module.BusinessObjects;
    
    [OptimisticLockIgnore]
    public class Department : BaseObject {
        //...
    }
    

    Disable Optimistic Locking For a Specific Property

    To disable optimistic locking for a specific property, decorate the property with the OptimisticLockIgnore attribute:

    using Microsoft.EntityFrameworkCore;
    
    namespace MainDemo.Module.BusinessObjects;
    
    public class Department : BaseObject {
        //...
        [OptimisticLockIgnore]
        public virtual string Office { get; set; }
    }