Architects / Developers

Dynamic Loading of Parent and Child Object’s Data: A Quick Guide

Bassem Marji

By Bassem Marji

You can dynamically load multiple records to parent and child objects simultaneously in a single DML call, using an External ID field on the parent object. By delving into this article, you will gain the following:

  • A thorough understanding of what the External ID field is and how it operates
  • A dive into how leveraging External IDs may streamline data integration process

Let’s get started…

Understanding External IDs

An External ID is a standard or custom field in Salesforce that generally holds identifiers coming from external systems such as ERPs or third-party applications.

An External ID supports the following field types:

  • Text
  • Email
  • Number
  • Auto-Number
  • Text Encrypted
READ MORE: A Beginner’s Guide to Salesforce Fields

Leveraging External IDs to Streamline Data Integration

Basically, associating a child record to its parent using an External ID field is an alternative to using the parent record ID field and necessitates the following:

  • Having a parent object with a custom field defined as External ID
  • Creating one or multiple parent records while specifying the External ID relative values
  • Setting a parent record as a nested sObject on the corresponding child records to create

Let’s look at the following practical examples to address a scenario involving the insertion of multiple accounts and contact records in either of two ways: basic and advanced.

The Basic Way

This method involves creating the accounts and then creating the contact records while specifying their parent accounts as nested records.

Refer to this code:

public class CreateParentChild {
    /**
     *Inserting Parent And Child records using multiple DML statements.
    */ 
    public static void basicWay() {
		//Inserting Accounts
    	List<Account> accountList = new List<Account>();
    	
    	for (Integer i=0; i<5; i++) {
        	accountList.add( new Account(Name = 'Test Account_' + i
            	                        ,External_ID__c = 'Test Account External_' + i 
                                    )
                	       );
    	}
    	insert accountList;
    
    	//Inserting Contacts
    	List<Contact> contactList = new List<Contact>();
    	for (Account acc: accountList) {
        	Contact con = new Contact( FirstName = 'First_Name'
            	                      ,LastName  = 'Last_Name'             
                	                  ,Account   = acc
        							 );
        	contactList.add(con); 
    	}
    	insert contactList;
        
    	//USAGE
		System.debug('Number of DML statements used so far: ' + Limits.getDmlStatements());
    }
    
    /**
     *Inserting Parent And Child records dynamically using a single DML statement.
    */ 
    public static void advancedWay() {
           final String parentObjAPIName = 'Account';
 		   final String childObjAPIName  = 'Contact';
              
           //Extracting RelationShip properties between child and parent objects
           String childToParentRelationShipFieldName = null;
           for (Schema.ChildRelationship cr: Schema.getGlobalDescribe()
                	                               .get(parentObjAPIName)
                    	                           .getDescribe()
             									   .getChildRelationships()
               ) 
           {
             if ( String.valueOf(cr.getChildSObject()) == childObjAPIName ) {
                  childToParentRelationShipFieldName =String.valueOf(cr.getField());
             }    
		   }
        
           //Getting the Relationship Name Between Parent and Child
           String childToParentRelationShipName = Schema.getGlobalDescribe()
                	                              .get(childObjAPIName)
                    	                          .getDescribe()
                                                  .fields
                                                  .getMap()
                                                  .get(childToParentRelationShipFieldName)
               									  .getDescribe()
                                                  .getRelationshipName();
           	
       	   List<SObject> parentList = new List<SObject>();
           List<SObject> childList  = new List<SObject>();
           List<SObject> resultList  = new List<SObject>();
        
	       for (Integer i=0; i<5; i++) {
               
                String external_ID = 'Test Account External_' + i;
                    
        		SObject parentObj = Schema.getGlobalDescribe().get(parentObjAPIName).newSObject();
        		parentObj.put('Name'           , ('Test Account_' + i) );
            	parentObj.put('External_ID__c' , external_ID );
            	parentList.add(parentObj);
                
            	//Create a clone of the Parent Object for foreign key reference
            	SObject parObjClone = Schema.getGlobalDescribe().get(parentObjAPIName).newSObject();
            	parObjClone.put('External_ID__c' , external_ID );
            	
            	SObject childObj = Schema.getGlobalDescribe().get(childObjAPIName).newSObject();
            	childObj.put('FirstName'      , ('First_Name_'+i) );
            	childObj.put('LastName'       , ('Last_Name_'+i) );
            	
               	childObj.putSObject(childToParentRelationShipName,parObjClone);
            	childList.add(childObj);
        	}
        
        	resultList.addAll(parentList);
        	resultList.addAll(childList);
        
        	try
            {
        	 insert resultList;
            } catch(Exception e) {
    	       System.debug('Exception=' + e);
        	}
        	
	    	//USAGE
			System.debug('Number of DML statements used so far: ' + Limits.getDmlStatements());
    }
}

Executing this method will consume two DML statements in terms of governor limits.

The Advanced Way

This method involves the following:

  • Specifying the names of the parent and child objects.
  • Extracting the properties of the relationship between child and parent objects.
  • Creating parent accounts.
  • Creating clones of parent accounts for foreign key references. This cloned object serves to overcome a System.DMLException.
  • Creating child records while adding the cloned parent object as a nested sObject throughout the relationship field.

Refer to this code:

public class CreateParentChild {
    /**
     *Inserting Parent And Child records using multiple DML statements.
    */ 
    public static void basicWay() {
		//Inserting Accounts
    	List<Account> accountList = new List<Account>();
    	
    	for (Integer i=0; i<5; i++) {
        	accountList.add( new Account(Name = 'Test Account_' + i
            	                        ,External_ID__c = 'Test Account External_' + i 
                                    )
                	       );
    	}
    	insert accountList;
    
    	//Inserting Contacts
    	List<Contact> contactList = new List<Contact>();
    	for (Account acc: accountList) {
        	Contact con = new Contact( FirstName = 'First_Name'
            	                      ,LastName  = 'Last_Name'             
                	                  ,Account   = acc
        							 );
        	contactList.add(con); 
    	}
    	insert contactList;
        
    	//USAGE
		System.debug('Number of DML statements used so far: ' + Limits.getDmlStatements());
    }
    
    /**
     *Inserting Parent And Child records dynamically using a single DML statement.
    */ 
    public static void advancedWay() {
           final String parentObjAPIName = 'Account';
 		   final String childObjAPIName  = 'Contact';
              
           //Extracting RelationShip properties between child and parent objects
           String childToParentRelationShipFieldName = null;
           for (Schema.ChildRelationship cr: Schema.getGlobalDescribe()
                	                               .get(parentObjAPIName)
                    	                           .getDescribe()
             									   .getChildRelationships()
               ) 
           {
             if ( String.valueOf(cr.getChildSObject()) == childObjAPIName ) {
                  childToParentRelationShipFieldName =String.valueOf(cr.getField());
             }    
		   }
        
           //Getting the Relationship Name Between Parent and Child
           String childToParentRelationShipName = Schema.getGlobalDescribe()
                	                              .get(childObjAPIName)
                    	                          .getDescribe()
                                                  .fields
                                                  .getMap()
                                                  .get(childToParentRelationShipFieldName)
               									  .getDescribe()
                                                  .getRelationshipName();
           	
       	   List<SObject> parentList = new List<SObject>();
           List<SObject> childList  = new List<SObject>();
           List<SObject> resultList  = new List<SObject>();
        
	       for (Integer i=0; i<5; i++) {
               
                String external_ID = 'Test Account External_' + i;
                    
        		SObject parentObj = Schema.getGlobalDescribe().get(parentObjAPIName).newSObject();
        		parentObj.put('Name'           , ('Test Account_' + i) );
            	parentObj.put('External_ID__c' , external_ID );
            	parentList.add(parentObj);
                
            	//Create a clone of the Parent Object for foreign key reference
            	SObject parObjClone = Schema.getGlobalDescribe().get(parentObjAPIName).newSObject();
            	parObjClone.put('External_ID__c' , external_ID );
            	
            	SObject childObj = Schema.getGlobalDescribe().get(childObjAPIName).newSObject();
            	childObj.put('FirstName'      , ('First_Name_'+i) );
            	childObj.put('LastName'       , ('Last_Name_'+i) );
            	
               	childObj.putSObject(childToParentRelationShipName,parObjClone);
            	childList.add(childObj);
        	}
        
        	resultList.addAll(parentList);
        	resultList.addAll(childList);
        
        	try
            {
        	 insert resultList;
            } catch(Exception e) {
    	       System.debug('Exception=' + e);
        	}
        	
	    	//USAGE
			System.debug('Number of DML statements used so far: ' + Limits.getDmlStatements());
    }
}

Executing this method will consume only one DML statement in terms of governor limits.

Note: This method works also when performing updates or upserts.

Hope this advanced method will help you optimize your data ingestion jobs, especially when you have a scarcity in terms of resources.

Summary

This example demonstrates a different approach for handling the creation of multiple parent and child records in a single call, using a custom External ID field defined on the parent object and efficiently managing the available resources.

Any thoughts? Leave them in the comments below!

The Author

Bassem Marji

Bassem Marji

Bassem is a certified Salesforce Administrator, a Project Implementation Manager at BLOM Bank Lebanon, and a Technical Author at Educative. He is a big fan of the Salesforce ecosystem.

Leave a Reply