Saturday, February 1, 2020

Approach: Dynamically insert records based on External Id with maintaining relationship

Motivation behind this


One of my mentees was struggling with approach and code sample for this below use case which motivates me on writing this post.


Use Case


Business has a requirement to view the data at Salesforce. Data will be provided from External System. External System's data is source of truth. External System will host webservice endpoint and developer could perform callout and fetch the data in JSON format.

For example, external system is maintaining Account and Inventory information. Those information should be fetched and insert the records.

Developer is also looking for an option to make the data mapping in a configurable way so that any field or Object name can be fetched on the fly and prepare the relationship among the objects and finally insert the data.


Solution Approach


Developer is trying to build up a solution with a help of Apex class and Custom Metadata Types as per following diagram.



For example, Account data is being provided from external system like below, this can be a JSON format. For better understanding plotting this in excel columns.



Since, external system's data is source of truth so we need to create External Id field on Account Object and Custom Inventory object (Inventory__c).

Account object will also have a lookup relationship to the Inventory object (relationship name: Inventory__r).

Let us assume, Account record with External Id = 123 and Inventory record with External Id = 125 have been created earlier.

So, when we insert Child Account B record then it will also maintain the relationship to the Parent Account A and Inventory record 125 through respective external Ids.

To make it configurable way of mapping, JSON attributes and Salesforce field Names should be maintained in Custom metadata types with the following information.


Here, main challenge is creating the instance of the object dynamically, add those fields using FieldAPINames and create records with maintaining the relationship.

For sake of simplicity, webservice callout and fetching records from JSON and fetching field mapping from Custom metadata types have been omitted.

Only challenging part with optimized code has been provided below:

Code Sample




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//create an instance of Account object, take this object name from Object field of custom metadata type.
String sObjectName = 'Account';
SObject acct = (SObject)(Type.forName('Schema.'+ sObjectName).newInstance());
//add fields based on FieldAPIName of Custom metadata types and values of JSON
acct.put('Name', 'Test Acct C');
acct.put('External_Id__c' ,'124');

//To relate to parent Account record, take this from Custom metadata type's 'Relationship Object' field 
String ParentObjName = 'Account'; //Relationship Object

//create an instance of related parent account object instance
SObject accRelationship = (SObject)(Type.forName('Schema.'+ ParentObjName).newInstance());
accRelationship.put('External_Id__c','123'); //Relationship Field API Name

//here mention Relationship API Name from Custom metadata type using putSObject method
acct.putSObject('Parent',accRelationship);

//similarly to relate Inventory record
String relatedLookupObjectName = 'Inventory__c';
SObject invRelationship = (SObject)(Type.forName('Schema.'+ relatedLookupObjectName).newInstance());
invRelationship.put('External_Id__c','125');
acct.putSObject('Inventory__r',relatedLookupObjectName);

//it can be added to a list and insert that
insert acct;




You can see that, to maintain parent relationship of the Account, Account object instance has been created and  External_Id__c has been mentioned and finally putSObject method of SObject has been used to specify related relationship.

Also, creating an instance of an object has done with reflection technique which is faster than SObject describe.

All the String values can be replaceable with dynamic values.

Sometimes, code looks simple to derive but it takes time to put in a proper approach which I have tried to portray here. Hope it helps.


Further Reading


No comments:

Post a Comment