Thursday 19 July 2012

Generic code for - "Owner Info in Formulas Workaround" by michael

I wrote some generic code for the idea by michael here. http://www.michaelforce.org/recipeView?id=a0G30000006aQgCEAU. Please go through it and appreciate this guy first.

Briefly, his idea in his words is:
"The basic idea is that while you can't use cross-object formulas on the Owner of a record... you CAN use a custom lookup relationship to the User object. So we're going to create our own lookup field and then make sure it is always synchronized with the standard Owner Field."


This is fantastic idea and i thought of writing some generic code for it, so that you can use it across the board for any sObject. Here is the generic code:


public with sharing class Util
{
 /* Global Variables and Constacts - Begin*/
 private static final string OWNER_FIELD_API_NAME = 'ownerId';
 /* Global Variables and Constacts - End*/

 /*
  Name : setOwnerCopyIfOwnerIsUser
  Parameters :
     i) lstSobjects : Pass the sobjects for which you want to set the "owner (lookup to user) field
     ii) lkFieldApiName : Pass the name of the "owner (lookup to User)" field Api name.
  Returns : Nothing, But the changes made to items of lstSobjects will reflect automatically in caller because of the default call by reference behavior.
  Description: The basic idea is that while you can't use cross-object formulas on the Owner of a record. you CAN use a custom lookup relationship to the User object. So we're going to create our own lookup field and then make sure it is always synchronized with the standard Owner Field  */
 public static void setOwnerCopyIfOwnerIsUser(List<sObject> lstSObjects, string lkFieldApiName)
 {
  try
  {
   /* Validate Inputs and exit in Invalid cases - Begin */
   // If there is no data to handle owner look up, exit.
   if(lstSObjects.isEmpty()) return;

   // Make a describe call to get the field api names of the sObject passed in.
   Schema.DescribeSObjectResult sObjectMeta = lstSObjects[0].getSObjectType().getDescribe();
    Map<String, Schema.SObjectField> sObjectfieldMap = sObjectMeta.fields.getMap() ;
  
    // If the sobject in context does not contain a field with the lookup field api name passed, exit.
    if(!sObjectfieldMap.containsKey(lkFieldApiName)) return;
    /* Validate Inputs and exit in Invalid cases - End */
  
    /* Fill the owner lookup field - Begin */
    for(sObject record : lstSObjects)
    {  
     // Check if the ownerId field is set a user Id or not.
     // This condition should avoid setting "owner lookup to user" field if the ownerId is a QueueId.
     if(record.get(OWNER_FIELD_API_NAME) != null &&
      ((string)record.get(OWNER_FIELD_API_NAME)).subString(0,3) == sObjectType.User.getKeyPrefix())
     {   
      record.put(lkFieldApiName, record.get(OWNER_FIELD_API_NAME));
     }
     else
     {
      //Incase of Owner is queue set the owner lookup field to NULL
      record.put(lkFieldApiName, null);
     }
    }
    /* Fill the owner lookup field - End */
  }
  catch(Exception ex)
  {
   system.debug('Unexpected error occurred in method setOwnerCopyIfOwnerIsUser(). Error: ' + ex.getMessage());
  }
 }
}


Please thank only michael for this if it helped you. :)

Wednesday 18 July 2012

Effectiving Aliasing in Force.com Apex

Effective aliasing in Aggregate Queries.
=========================================
How often do you use aliases in Aggregate Queries. Not much? Then please see an example below how important it is.

What would you do If you want to create a map for an aggregate Query and want the grouping field as the key of Map with less effort?
You will try something like below:
Map<string, AggregateResult> mapCountPerUniqueId = new Map<string, AggregateResult>([select case__c, count(Id) from Payer_Involved__c where uniqueId__c != null group by case__c]);
                     
But the above statement will give an exception "Row with null Id at index: 0". So you will abandon the above approach and go for a for loop. But dont give up on the aggregate query's ability yet. With simple aliasing you will not need to write that unnecessary for loop. So, How can it be done? Simple. See the above statement reformed below:

Map<string, AggregateResult> mapCountPerUniqueId = new Map<string, AggregateResult>([select case__c Id, count(Id) piCount from Payer_Involved__c where uniqueId__c != null group by case__c]);
                     
What was the difference you found? Aliases! Isn't it? Yes. They do the magic. If you give "Id" as alias to the first field of the aggregate query, it will simply assume that as the grouping key. And if you observe I used another alias "piCount" which is more meaning full than "expr1" that you would typically use to extract aggregate result values. But, hasn't the word "piCount" made my aggregate query easily understandale.