Lets say you have a parent record on an object that receives data from an external source, and every time new data comes in INSTEAD of updating an existing record is simply creates a NEW record. The Id changes (obviously) but there's an external Id that doesn't change. The old records have a status__c field thats a picklist with a text value of inactive, while the new record has the status active. That parent object has child objects that also change each time, how would i go about re-parenting those child objects to the active record.

I know i have to codemonkey something up, but i can't think of how to reparent a child record going off of parent values (ie the external Id and the status field)

  • How is the original record's Status__c value being updated from active to inactive? Is that handled by a data job (or whatever is pushing the new records in), or is there a trigger already in place? – Shane Steinfeld Oct 2 '18 at 0:08

Assuming the record you want to re-parent from is the most-recently modified inactive record with the same External Id, and...

Assuming the old parent records' status is changed to 'inactive' before the new parent records are inserted...

A trigger like this one, fired After Insert of the new records should work:

List<ParentObject__c> newParents = Trigger.new();
Integer recordCount = newParents.size();
Map<String, Id> externalIds_to_newParentIds = new Map<String, Id>();

for(ParentObject__c p : newParents){
    externalIds_to_newParentIds.put(p.ExternalId__c, p.Id);

// Get all the old (current) parent records, and the child records from each parent
List<ParentObject__c> oldParents = [SELECT Id, 
                                           (SELECT Id, Parent.ExternalId__c FROM ChildObject1__r),
                                           (SELECT Id, Parent.ExternalId__c FROM ChildObject2__r)
                                      FROM ParentObject__c 
                                     WHERE ExternalId__c IN :externalIds_to_newParentIds.keySet()
                                       AND Status__c = 'inactive'
                                  ORDER BY LastModifiedDate DESC
                                     LIMIT :recordCount];

List<sObject> recordsToUpdate = new List<sObject>();

for(ParentObject__c p : oldParents){

    for(ChildObject1 c : p.ChildObject1__r){
        c.ParentId = externalIds_to_newParentIds.get(c.Parent.ExternalId__c);

    for(ChildObject2 c : p.ChildObject2__r){
        c.ParentId = externalIds_to_newParentIds.get(c.Parent.ExternalId__c);
  • 1
    any recursion issues to be careful about? – cropredy Oct 2 '18 at 1:59
  • @cropredy -- Now you have me paranoid thinking I've missed something ;) I don't think so, as long as the trigger fires After Insert. The one thing I am worried about is what would happen if an inactive ParentObject record were modified between the time the old parents were deactivated and this trigger fired. That would mean we wouldn't get all of the ParentObject records we need in the oldParents query. If that's a possibility, we can't use "LIMIT : recordCount'. Without some other way of limiting the query, and assuming old records aren't deleted, it would get less efficient over time. – Shane Steinfeld Oct 2 '18 at 2:32
  • @Shane Steinfeld You're assumptions are correct, the original trigger is after insert. But i want to pull all child records from all inactive parent records and re-parent them to the current active record; sometimes there's 5 inactive parent records. But i think i may be able to do it with this as an outline. – enossir Oct 2 '18 at 18:36
  • @ShaneSteinfeld The status is modified in the after insert trigger – enossir Oct 2 '18 at 18:50
  • @enossir -- perfect. Yes, you should be able to modify this and add it to your after insert trigger then. Let me know if you have any trouble. – Shane Steinfeld Oct 2 '18 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.