Tuesday, 15 March 2022

How to retrieve populated fields from a sObject ?

 As part of summer 16, the sObject method getPopulatedFieldsAsMap() was released. This method will return a map of populated field names and their corresponding values. The map contains only the fields that have been populated in memory for the SObject instance.

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_sobject.htm#apex_System_SObject_getPopulatedFieldsAsMap

Here are certain use cases to  this method.

1.  Fields are queried in the SOQL Statement

Account acc = [SELECT id,name,phone,Gender__pc From Account
               WHERE id = '0011F00000zJIvwQAG'];
System.debug('acc->'+acc);
Map<StringObject> accMap = acc.getPopulatedFieldsAsMap();
system.debug('Fields name-->'+accMap.keySet());
for (String fieldName : accMap.keySet()){
    System.debug('field name is ' + fieldName + ', value is ' + 
        accMap.get(fieldName));

}
OutPut -
Note - Id, and Recodtype will come by default even if it is not added in Query.
We can also use dynamic query for this.

public static void getPopulatedFields(List<String> fields, String objName) {
    String soql = ' Select ' + String.join(fields, ',') + 
                  ' From ' + objName;
    
    for (sObject obj : Database.query(soql)) {
       Map<StringObject> fieldValues = obj.getPopulatedFieldsAsMap();
       for (String fieldName : fieldValues.keySet()) {
           System.debug(fieldName + '=' + fieldValues.get(fieldName));
       }
    } 
}
// Invoking method
List<String> fields = new List<String>{'Name','Phone','Gender__pc'};
getPopulatedFields(fields, 'Account');

2. Fields are explicitly set before calling the getPopulatedFieldsAsMap() method.
Account acc = new Account(Name='Test Acc',Phone='1122334565');
//sert acc;
Map<StringObject> accMap = acc.getPopulatedFieldsAsMap();
system.debug('Fields name-->'+accMap.keySet());
for (String fieldName : accMap.keySet()){
    System.debug('field name is ' + fieldName + ', value is ' + 
        accMap.get(fieldName));

}
OutPut -

3. Using Relationship Query. Child to parent.

Account acc = [SELECT id,name,phone,Gender__pc,owner.Name,Createdby.Email,
SHC_Facility__pr.Facility_Short_Name__c,(Select CaseNumber, Status From Cases)  
               FROM Account
               WHERE id = '0011F00000zJIvwQAG'];
Map<StringObject> accMap = acc.getPopulatedFieldsAsMap();
system.debug('Fields name-->'+accMap.keySet());
It will print -
13:50:17:036 USER_DEBUG [6]|DEBUG|Fields name-->
{CreatedBy, CreatedById, Gender__pc, Id, Name, Owner, OwnerId, Phone, RecordTypeId,
SHC_Facility__pc, ...}
How will we get fields of related objects such as Owner or CreatedBy or
SHC_facility__pr

User uRec = (User)accMap.get('Owner'); Map<String, Object> userMap = uRec.getPopulatedFieldsAsMap(); system.debug('Owner Fields name-->'+userMap.keySet()); User createdByRec = (User)accMap.get('CreatedBy'); Map<String, Object> CreateduserMap = createdByRec.getPopulatedFieldsAsMap(); system.debug('Created By Fields name-->'+CreateduserMap.keySet()); Rehabilitation_Center__c facility = (Rehabilitation_Center__c)accMap.get('SHC_Facility__pr'); Map<String, Object> FaciLityMap = facility.getPopulatedFieldsAsMap(); system.debug('FaciLityMap Fields name-->'+FaciLityMap.keySet());

// To get case record fields and value
List<Case> caseList = (List<Case>)accMap.get('Cases');
System.debug('caseList--'+caseList);
Map<String, Object> caseMap = caseList[0].getPopulatedFieldsAsMap();
System.debug('caseMap-fields-'+caseMap.keySet());

To know value we need to iterate over map keyset and get value.

We can also write generic code which will support all objects.
/* method to expand map of key to find out parent or child objects and get value 
and field name after
*/
public void getPopulatedFields(Map<StringObject> fieldValues) {
   for (String fieldName : fieldValues.keySet()) {
       if (fieldValues.get(fieldName) instanceof List<sObject>) {
           System.debug('------Begin Child------');
           getPopulatedFields((List<sObject>) fieldValues.get(fieldName));
           System.debug('------End Child------');
       } else if (fieldValues.get(fieldName) instanceof sObject) {
           System.debug('------Begin Parent------');
           sObject obj = (sObject) fieldValues.get(fieldName);
           getPopulatedFields(obj.getPopulatedFieldsAsMap());
           System.debug('------End Parent------');
       } else {
           System.debug(fieldName + '=' + fieldValues.get(fieldName));
       }
   }
}
/* method to iterarte over child recordList and call getPopulatedFields passing result
 of getPopulatedFieldsAsMap
*/
public void getPopulatedFields(List<sObject> objs) {
   for (sObject obj : objs) {
        getPopulatedFields(obj.getPopulatedFieldsAsMap());
    }
}

/* method will accept object name and fields name, get records by using dynamic query
 and call getPopulatedFields
*/
public void getPopulatedFields(List<String> fields, String objName) {
    String soql = ' Select ' + String.join(fields, ',') + 
                  ' From ' + objName;

    List<sObject> objs = Database.query(soql);
    getPopulatedFields(objs);
}

Invoking methods.
List<String> fields = new List<String>
{'Name,phone,Gender__pc,owner.Name,Createdby.Email,
SHC_Facility__pr.Facility_Short_Name__c, (Select CaseNumber, Status From Cases)'};
getPopulatedFields(fields,'Account')

No comments: