The only way that you can guarantee that this is done would be to put your logic in a trigger. Your trigger would be on the top level object that you wish to update the other two fields from. You will need to find the objects in your trigger that you wish to update and you can add them to a List<SObject>
and update them both simultaneously. See below pseudo based on your supplied pseudo...
trigger CustomObjectTrigger on Custom_Object_1__c( before insert, before update, after insert, after update, before delete, after delete ){
Map<Id, SObject> newMap = Trigger.newMap;
List<SObject> object2List = [ SELECT Id, Custom_Object_1_MD_or_Lookup__c, some_other_fields__c FROM Custom_Object_2__c WHERE Custom_Object_1_MD_or_Lookup__c IN: newMap.keySet() ];
List<SObject> object3List = [ SELECT Id, Custom_Object_1_MD_or_Lookup__c, some_other_fields__c FROM Custom_Object_3__c WHERE Custom_Object_1_MD_or_Lookup__c IN: newMap.keySet() ];
Map<String, List<SObject>> obj2MapByObj1Id = new Map<String, List<SObject>>();
Map<String, List<SObject>> obj3MapByObj1Id = new Map<String, List<SObject>>();
// organize all sibling obj 2 by the parent for quick access
for( SObject record : object2List ){
String objParentId = String.valueOf( record.get( 'Custom_Object_1_MD_or_Lookup__c' ) );
List<SObject> siblings = obj2MapByObj1Id.containsKey( objParentId ) ? obj2MapByObj1Id.get( objParentId ) : new List<SObject>();
siblings.add( record );
obj2MapByObj1Id.put( objParentId, siblings );
}
// organize all sibling obj 3 by the parent for quick access
for( SObject record : object3List ){
String objParentId = String.valueOf( record.get( 'Custom_Object_1_MD_or_Lookup__c' ) );
List<SObject> siblings = obj3MapByObj1Id.containsKey( objParentId ) ? obj3MapByObj1Id.get( objParentId ) : new List<SObject>();
siblings.add( record );
obj3MapByObj1Id.put( objParentId, siblings );
}
List<SObject> updateList = new List<SObject>();
// iterate in the trigger records and create an update list
for( Custom_Object_1__c record : Trigger.new ){
List<SObject> obj2Children = obj2MapByObj1Id.containsKey( record.Id ) ? obj2MapByObj1Id.get( record.Id ) : new List<SObject>();
List<SObject> obj3Children = obj3MapByObj1Id.containsKey( record.Id ) ? obj3MapByObj1Id.get( record.Id ) : new List<SObject>();
if( some logic here ){
... update obj2 child(ren)
... update obj3 chid(ren)
updateList.addAll( obj2Children ); // make sure they get in the update list
updateList.addAll( obj3Children ); // make sure they get in the update list
}
}
// update as necessary
if( !updateList.isEmpty() ){
Database.SaveResult[] mResult = Database.update( updateList, false ); // using false here allows you to update what can be updated and the rest will return an error in the SaveResult
for( Database.SaveResult result : mResult ){
if( !result.isSuccess() ){
// do some stuff with your errors
}
}
}
}
This of course is a very generic written solution given very generic condition but i think you get the idea.
We use the List<SObject>
here since we can save the generic objects with a single save and they can be different declared types. The generic List<SObject>
holds some power in that.
Some things to note
You will be limited to the number of different types of SObject
that can exist within the same list. I would suggest to keep the different SObjects down to 2 or 3 to avoid getting errors when saving due to too many types in your List<SObject>
If not updating additionally the object that you are triggering on, I would also suggest that you check the trigger context that you are in by using:
if( Trigger.isAfter && Trigger.isUpdate ){
.... your logic
}
if you are going to update the current object in your trigger - you should use before update
if( Trigger.isBefore && Trigger.isUpdate ){
.... your logic
}
Additional Links
HERE is a good blog post that outlines this behavior that would be helpful as another example.