Thursday, February 12, 2015

Distinct keyword in salesforce


Distinct Records in Salesforce

In a table or a Object(In Salesforce), a column may contain many duplicate values; and sometimes you only want to list the different (distinct) values.
The DISTINCT keyword can be used to return only distinct (different) values.
In SQL we can write a Query to extract distinct records from table by making use of a sample Query like this 
SELECT DISTINCT column_name,column_name
FROM table_name;
But in SOQL there is no distinct keyword to do the operation and it is really boring to write out own custom logic to pick the distinct values. Please care to drop this idea in App exchange.
Eventhough Salesforce suggests the use of aggregate methods(Partial solution) to solve this I felt it's complex to implement it and it didn't work as expected. So I need to come up with a custom logic to pick distinct records from a custom object and insert it in to a unrelated second object.
/*****
***Description: The unique distinct records are picked from
***sessions aggregate object and inserted as unique records in detail reporting group object
******/


trigger InsertDistinctReportGroudId on Sessions_Aggregate__c (after insert) { 
//Collect the whole List of Session Aggregate data
        list SAlist = [select id,Reporting_Group_Name__c,SOName__c from Sessions_Aggregate__c where Reporting_Group_Name__c!=null  limit 9999];
        system.debug('SAlist '+SAlist);
//create a new set to pick the unique records and add the distinct values inside the set
        Set s1 = new Set();    
    for(Sessions_Aggregate__c c:SAlist){
//Iterate thhru the main list and assign the distinct values from a set
        s1.add(c.Reporting_Group_Name__c);
    }
        system.debug('*****'+s1.size());
//Collect the pre-Existing records in the second custom object to compare 
        list oldRGlist = [select ReportingGroupName__c from Detail_Reporting_Group__c limit 9999];
        List distinctRGnames = new List();
//Create sets to compare the existing record values of the second object with the 1st object
        Set s2 = new Set();
        Set s3 = new Set();   
    if(oldRGlist.size()>0){
    for(Detail_Reporting_Group__c S:oldRGlist){
        s2.add(S.ReportingGroupName__c);
    }
    }
    for(string s : s1){
        if(s2.contains(s)){
//if 1st object list contains any of the field values from the 2nd object the remove the repeating value from the 2nd object set.
            s2.remove(s);    
        }
    else{
//if there is no duplicates the add the 2nd obj value to the 1st object list's value 
    s3.add(s);
     }           
    }    
//Now we got all the distinct values in the set now add these value in to a master list for Insertion.
        distinctRGnames.addAll(s3);
        system.debug('+distinctRGnames+'+distinctRGnames);
          list<Detail_Reporting_Group__c> RGlist= new list<Detail_Reporting_Group__c>();
          for (integer i=0;i<distinctRGnames.size();i++){
            Detail_Reporting_Group__c DGR=new Detail_Reporting_Group__c();
            DGR.ReportingGroupName__c=distinctRGnames[i];
             RGlist.add(DGR);    
    }
//Insert The main List
    insert RGlist;


This would serve the purpose of collecting the distinct records of one object and inserting it in to another object.

Authored by: Nirmal Christopher,
 Salesforce.com Certified Developer, 
Technical Consultant, 
Global Tech & Resources, Inc. (GTR).


Creating Queues Programatically (Queue is not associated to the S object Type)

How to Create Queues Programatically in Salesforce

There will be a situation where you need to create queues programatically. Before architecting  the technical complexity there are few things taken on account 

There is two types of objects in Salesforce setup objects and  non setup objects. Set up objects doesn't allow DML operation. Please follow the link to check the list of setup and non setup objects which allow the DML operation.


you see the link Q Sobject is added in to the list. So we cannot create the Queues programatically by any direct means. But there is a workaround for this limitation.

The scenario I worked was to create new Queues based on the field value from a custom object when the record in the custom object is getting created.

So I would require a after insert trigger on the custom object to pick the name of the queue from the field value and a @future class to orchestrate the queue creation.

/*****

Description: This trigger creates queue based on the detail reporting group names

*****/

trigger CreateNewQueues on Detail_Reporting_Group__c (after insert) {     
  List newGroups = new List();
  for (Detail_Reporting_Group__c sa: Trigger.new) {
  if(sa.ReportingGroupName__c!=null){
     newGroups.add(new Group(name='RG-'+sa.ReportingGroupName__c,type='Queue'));     
     }
  }
  insert newGroups;
  Set groupids= new Map (newGroups).keySet();
  // call in future context to avoid MIXED DML conflicts
  sessionhandler.createQueue(groupIds); 


//Apex Class to handle the session to create Queues Asyncronously

public class SessionHandler{
@future
public static void createQueue(Set groupIds) {
List newQueueSobject = new List();
String clipoff;
for (Id queueId : groupIds) {
newQueueSobject.add(new QueueSObject(SobjectType='Sessions_Aggregate__c',QueueId=queueId));
}
system.debug('NEWRECORD'+newQueueSobject);
try{
insert newQueueSobject;
}
catch(exception e){
system.debug('EEEEEEEEEEEEEEEEEEE'+e);
}   
}  
}

We would require a future annotation to insert records on the setup objects asynchronously. And pass the parameters via signature groupIds to create new queue records based on the file name.



Authored by: Nirmal Christopher,
 Salesforce.com Certified Developer, 
Technical Consultant, 
Global Tech & Resources, Inc. (GTR).

Wednesday, February 11, 2015

Nested For Loop is Infected



If we have a scenario of comparing two different lists and performing a logic it works like a Odo meter of the car. The Inner loop executes first and outer loop is executed later. Consider the scenario of comparing two different lists and doing a field update based on the comparison.

Lets take two different lists

List<account>accountlist=[select id, name from account limit 9999];

List<customobject>customobjList=[select id, textvalue, lookupaccount from custom object limit 9999];

based on the text value of a field from a custom object the logic should fetch the related account name and update the look up field in the custom object.

This scenario can be achieved as follows

for(customobjList obj:customobjList){
    for(Account a:accountlist){
      obj.textvalue=a.name;
         }
}

In triggers the code needs to be properly bulkifie

The above piece of code will work fine. But the list defined inside the inner for loop will soon hit the governor limits before we can expect.

How to avoid this?

By making proper usage of Salesforce Collections

The below code will also perform the same logic but it handles the governor limits very well

list<account>acc=[select id,name from account limit 9999];
        map<string,account>accfinalmap=new map<string,account>();
    for(account acc1:acc){
        accfinalmap.put(acc1.name,acc1);
    }

    for(customobject sa3:trigger.new){
                if(accfinalmap.containskey(sa3.textvalue)){
                sa3.lookupaccount =accfinal.id;
              }
    }


By making use of the Collection times effectively we can control the governor limits at ease.


Authored by: Nirmal Christopher,
 Salesforce.com Certified Developer, 
Technical Consultant, 
Global Tech & Resources, Inc. (GTR).