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
Interesting post. I’ve done the same thing by using a lookup filter. Because the filter is re-evaluated every time the Detail record is updated, disallowing certain values on the Master record will fire an error.
Plus, this requires no Apex!
For more information, see http://www.x2od.com/2009/10/06/filtered-lookups-validation-rules-and-order-of-execution.html.