Oh my god. It's full of code!

Salesforce Apex Prevent Record Editing/Saving after condition

Hey all, this is just kind of a handy snippit. It will allow you to prevent a record from being edited if a condition on the record is met. This is nice for locking down a record as soon as some kind of field is set. Like say you have a status picklist that sends in a record for approval once it is in the stopped status and you want to make sure nobody modifies it, this will do that for you. This method is super dynamic. I can take maps of any kinds of sObjects, check any field for any value and return any error message you like. You would run this from a before update trigger. You pass the method the trigger.oldMap, trigger.newMap, the Id of the field that puts the record in the locked state, the value that field must have to be locked, and an error message to return. You would call it like this (provided you had saved the method in a class called utilities).

utilities.preventRecordEdit(Trigger.oldMap, Trigger.newMap, 'status__c', 'Stopped', 'Stopped timers may not be modified');
    public static void preventRecordEdit(map<id,sObject> oldObjects, map<id,sObject> newObjects, string controllingField, string lockingValue, string errorMessage)
    {
       //get the type of object this list is, like contact, account, etc
        Schema.sObjectType objectType = oldObjects.values().getSObjectType();
        
        //global describe of objects
        Map<String, Schema.SObjectType> globalDescribe = Schema.getGlobalDescribe(); 
        
        //describe object
        Schema.DescribeSObjectResult objectDescribe = objectType.getDescribe();
        
        //get all the valid fields on this object
        Map<String, Schema.SobjectField> objectFields = objectType.getDescribe().fields.getMap();
                
        for(sObject oldObject : oldObjects.values())
        {
            if(oldObject.get(controllingField) == lockingValue)
            {
                sObject newObject = newObjects.get((id) oldObject.get('id'));
                for(string fieldName : objectFields.keySet())
                {
                   if(oldObject.get(fieldName) != newObject.get(fieldName))
                   {
                       sObject actualRecord = (sObject) Trigger.newMap.get((id) oldObject.get('id'));
                       actualRecord.addError(errorMessage);
                   } 
                }                
            }
        }
    }

Not sure if there is an easier way, but if nothing else, it’s a cool tech demo for super dynamic Apex Code 😛 Hope it helps someone.

6 responses

  1. This is great code. I just wonder when it would be better to use this instead of a validation rule.

    January 19, 2012 at 3:42 pm

    • You know, when I wrote this, I was thinking the ischanged feature of validation rules only checked a field, but now I am thinking it actually checks the whole object. If that is the case, then yes, this code is useless. I for some reason remember having a hard time getting a rule running that checked every field on an object for changes. Could have just been me being dumb.

      January 19, 2012 at 4:25 pm

      • I just checked. In a validation rule, the only way I know of to see if a field has changed is the ischanged function and that only checks one field at a time, so you’d need an ischanged for every field on the object, and have to fix that validation rule every time a field was added or removed from that object. this apex code is completely dynamic, just set it and forget it.

        January 19, 2012 at 4:29 pm

  2. Also, fun fact: field updates that fire as a result of an approval process bypass validation rules, but not triggers. Using a trigger is technically safer.

    September 29, 2012 at 8:31 pm

  3. Guy

    Nice piece of code! Too bad you have to use all these lines of code and describe calls to do this simple check in SF.
    I once implemented the following point-and-click solution:
    1. create a checkbox field called ‘Record locked’.
    2. create a workflow rule that triggers on each record edit, and if the record status is ‘Stopped’ (or any applicable value), sets the checkbox field to ‘TRUE’ (checked).
    3. create a validation rule that checks if the priorvalue of the ‘Record locked’ checkbox field is TRUE. If so, raise an error.
    This is also easier to deactivate for an administrator, if something needs to be temporarily fixed (does not require an APEX deployment).

    April 2, 2013 at 8:40 am

  4. Hi, all is going fine here and ofcourse every one is sharing data, that’s truly excellent, keep up writing.

    July 7, 2013 at 2:49 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s