[SalesForce] prevent Dirty Updates theself when overriding Save in a controller extension

The standard behavior (tested on Opportunities) is that Salesforce seems to handle dirty updates / save conflicts as expected:

  1. User A opens Opportunity X
  2. User B opens Opportunity X
  3. User A modifies and saves Opportunity X
  4. User B modifies and tries to save Opportunity X
  5. User B sees a conflict error and CANNOT override unseen changes from User A

When I try this on a custom object with a controller extension that has a custom doSave() method that calls standardController.save() the behavior is different and has dirty updates.

  1. User A opens Custom Object X
  2. User B opens Custom Object X
  3. User A (implicitly by a triggered Batch job) modifies and saves Custom Object X
  4. User B modifies and SUCCESSFULLY saves Custom Object X
  5. User B sees a has reverted all changes that were saved by User A

The problem is 5. User B has accidentally overriden all the changes made by User A just because he still has them in memory.

Do I need to handle / prevent this on my own in my controller extension?
Or should I call update instead of standardController.save() in my custom save method?

Best Answer

Salesforce DOESN'T handle this in custom save actions and doing an update instead of controller.save() makes no difference.

One solution would be to re-read the record from the database in your controller extension save() method, before committing the record (save/update), and compare the re-read SystemModstamp with the SystemModstamp of the record in your viewstate.

You will need to use controller.addFields(new List{'SystemModstamp'}) in the controller extension constructor if your page does not display the SystemModstamp.

If the SystemModstamps are different you know that the record has been modified and you can decide what to do.

For example:

public with sharing class OpportunityController
{
    ApexPages.StandardController m_controller;

    public OpportunityController(ApexPages.StandardController controller)
    {
        m_controller = controller;
        m_controller.addFields(new List<String>{'SystemModstamp'});
    }

    public ApexPages.PageReference save()
    {
        Opportunity record = (Opportunity) m_controller.getRecord();
        Opportunity dbRecord = [select SystemModstamp from Opportunity where Id=:record.Id];
        if(record.SystemModstamp!=dbRecord.SystemModstamp)
        {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'Someone else edited the record'));
            return null;
        }
        return m_controller.save();
    }
}
Related Topic