Constraining a detail field depending on a master field in a trigger

I’ve implemented this pattern several times with slight variations and each time had to do some head scratching to get it right. So here is the pattern expressed in somewhat abstract terms. The aim is to disallow a change to a Detail object field if its Master object has a field of a particular value. In my case these have been status fields.

Here is the trigger:

trigger DetailBeforeTrigger on Detail__c (before insert, before update) {
    // Create a map of the master object id to the detail objects
    Map<Id, List<Detail__c>> masterToDetails = new Map<Id, List<Detail__c>>();
    for (Detail__c newDetail : Trigger.new) {
        Detail__c oldDetail = Trigger.oldMap != null ? Trigger.oldMap.get(newDetail.Id) : null;
        String oldStatus = oldDetail != null ? oldDetail.Status__c : null;
        String newStatus = newDetail.Status__c;
        // Only add where the field has changed and to the specific value
        if (oldStatus != newStatus && newStatus == 'Approved') {
            List<Detail__c> ds = masterToDetails.get(newDetail.Master__c);
            if (ds == null) {
                ds = new List<Detail__c>();
                masterToDetails.put(newDetail.Master__c, ds);
            }
            ds.add(newDetail);
        }
    }
    // Add an error to the detail objects where the master field has a particular value
    if (masterToDetails.keySet().size() > 0) {
        for (Master__c m : [select Id, Status__c from Master__c where Id in :masterToDetails.keySet()]) {
            if (m.Status__c == 'Closed') {
                for (Detail__c d : masterToDetails.get(m.Id)) {
                    d.Status__c.addError('Detail Status cannot be "Approved" when the Master Status is "Closed"');
                }
            }
        }
    }
}

This code illustrates:

  • Checking if a field value has changed and only doing work if it has
  • Holding the 1:Many information in a Map
  • Ensuring only one SOQL query is done whether there is one Detail object or many
  • Reporting the error on a field so that it is clearly presented in the default UI

1 thought on “Constraining a detail field depending on a master field in a trigger

Leave a comment