Apr 26, 2011

System Debug

Its very hectic to debug when we have too many script statements. Most of the time when we apply System.debug in our code with many script statement we get :


*********** MAXIMUM DEBUG LOG SIZE REACHED ***********


I get frustrated with this and started rolling over the pdf which says there is a solution for this. Now if I want to see a specific line debug which is coming almost in the end of our code so I will simply write this where I want to get the debug in my code :
System.debug(Logginglevel.ERROR , ' ::::::: My Debug :::::::::::::') ;
And after this some steps to be done
  1. Create Debug logs from "Monitoring"
  2. Create Filters :
    • Database : NONE
    • Workflow : NONE
    • Validation : NONE
    • Callouts : NONE
    • Apex Code : ERROR
    • Apex Profiling : NONE
    • Visualforce : NONE
So when I execute my code only debug with Logginglevel.ERROR will be displayed. Isn't this useful. 

Enjoy the power of salesforce.

Apr 15, 2011

Pagination in Salesforce

We sometimes need to display many records on UI, so it doesn't look good when you display 10000 records on single page. Pagination is the best option you can opt for.


Now question is how you can apply pagination in salesforce with native salesforce look and feel. So here is the answer of this.


Visualforce Page Code :
<apex:page controller="pagingControllerForUser">
    <apex:form >
        <apex:pageBlock >
            
            <apex:pageMessages id="pgm"/>
            
            <apex:pageBlockButtons >
                <apex:commandButton value="Search" action="{!Search}"/>
            </apex:pageBlockButtons>
            
            <apex:pageBlockSection >
                <apex:pageBlockSectionItem >
                    <apex:outputLabel value="User Name"/>
                    <apex:inputText value="{!usr.Name}"/>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>

        </apex:pageBlock>

        <apex:pageBlock rendered="{!IF(AllSearchUsers.size != null && AllSearchUsers.size > 0, true , false)}">
            <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav2">
              Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
                  <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
                  <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
                  <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
                  <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
                  &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
                  <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
                  <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
                  <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
                  <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>          
              </apex:outputPanel>
            
            <apex:pageBlockSection columns="1">
                <apex:pageBlockTable value="{!AllSearchUsers}" var="UR">
                    <apex:column headerValue="Name" value="{!UR.Name}"/>
                    <apex:column headerValue="Email" value="{!UR.Email}"/>
                    <apex:column headerValue="Phone" value="{!UR.Phone}"/>
                    <apex:column headerValue="Department" value="{!UR.Department}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
            
            <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav">
              Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
                  <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
                  <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
                  <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
                  <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
                  &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
                  <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
                  <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
                  <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
                  <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>          
              </apex:outputPanel>

        </apex:pageBlock>

    </apex:form>
</apex:page>


This page will show a input field where you can enter user name to be searched. Now when you click search all user by that name get searched, lets say I search with "Test Test". I have 8 users with that name in my organisation. 5 record will be shown at a time on screen, it will be displayed like this.





When we click "Next Page" next 5 records will be displayed, in this case 3 records. Screen will come up like this.





Apex Code :
public class pagingControllerForUser
{
    public List<User> AllSearchUsers
    {
        get
        {
            if(con != null)
                return (List<User>)con.getRecords();
            else
                return null ;
        }
        set;}
    
    public User usr {get; set;}
    
    //Controller
    public pagingControllerForUser()
    {
        AllSearchUsers = new List<User>() ;
        usr = new User() ;
    }
    
     public PageReference Search()
    {   
        if(usr.Name != null)
        {
            con = new ApexPages.StandardSetController(Database.getQueryLocator([select Id , name , email , phone, Department from User where name = :usr.Name]));
 
            // sets the number of records in each page set
            con.setPageSize(5);
        }
        else
        {
            con = null;
        }
        return null ;
    }
    
    //Instantiate the StandardSetController
    public ApexPages.StandardSetController con{get; set;}
    
    //Boolean to check if there are more records after the present displaying records
    public Boolean hasNext
    {
        get
        {
            return con.getHasNext();
        }
        set;
    }
 
    //Boolean to check if there are more records before the present displaying records
    public Boolean hasPrevious
    {
        get
        {
            return con.getHasPrevious();
        }
        set;
    }
 
    //Page number of the current displaying records
    public Integer pageNumber
    {
        get
        {
            return con.getPageNumber();
        }
        set;
    }

    //Returns the previous page of records
    public void previous()
    {
        con.previous();
    }
 
    //Returns the next page of records
    public void next()
    {
        con.next();
    }
}


Any query about this is welcomed.


Cheers

Apr 11, 2011

Saving Script Statements

Hi All,


Many of you must aware of this but would like to share with all.


Generally when we write a apex code we don't focus on saving the script statements, but when we are working with code in bulk then we should take care of our script statements to reduce the processing of our code and also to avoid the governor limit of 200,000.


Now if we want to fetch ids of all account from my organisation, one generally use this code:

//Fetching all accounts
List<account> accObj = [select Id from account limit 50000] ;

//Creating set of all account Ids
List<id> accIds = new List<id>() ;

//Fetching Account ids
for(Account acc : accObj)
{
 accIds.add(acc) ;
}
//Now we use this list of account ids in other queries




Now if the query will return 50000 records then for loop will execute 50000 script statements. Now to avoid this we can simply write:

//Fetching all account in map
Map<id,account> aMap = new Map<id,account>([Select Id,Name from Account limit 50000]);

//Creating list of accounts
List<account> accList = aMap.values() ;

//Creating set of ids
Set<id> accIds = aMap.keySet() ;




Now if any query returns sObject as return type then also we can use this approach by typecasting it like this :

//Your dynamic query
String accountDynamicQuery = 'select id from account limit 50000' ;

//Typecasting it to map
Map<id,account> mapAcc = new Map<id,account>((List<account>)Database.query(accountDynamicQuery));




Now when we insert a object lets say if we want to insert account with values in some fields then we write:

Account accObj = new Account();
accObj.Name = 'Test' ;
accObj.Fax = '123445657' ;
accObj.Phone = '123456789' ;
insert accObj ;



Instead of this we can write this to save our script statements:

Account accObj = new Account(Name = 'Test' , Fax = '12345657' , Phone = '123456789') ;
insert accObj ;



Cheers

Mar 21, 2011

Issue With Ajax In IE9 (No such interface supported)


Hi All,


Today I found something very interesting and would like to share with you all.


I was facing error "No such interface supported" when I hit button on my custom page in IE9, but it was working properly on IE8. On click of this button controller method is called using AJAX, after that page messages is rendered. Here is the visualforce code :
<apex:page controller="IE9IssueController">
    <apex:form >

        <apex:pageMessages id="PM" />

        <apex:pageBlock title="IE9 Issue Page">

            <apex:pageBlockButtons >
                <apex:commandButton value="Hit" action="{!Hit}" reRender="PM"/>
            </apex:pageBlockButtons>
            
            <apex:outputLabel value="Hit the button, if info message displays that means action function is completed successfully else problem occured."/>
                        
        </apex:pageBlock>
    </apex:form>
</apex:page>

And here is my apex code :
public class IE9IssueController
{
    public IE9IssueController()
    {
    }
    
    public void Hit()
    {
        Apexpages.addMessage(new Apexpages.Message(ApexPages.Severity.INFO, 'You clicked the button!'));
    }
}
Now I was unable to find the exact problem but was able to get the work around of it. This line put the browser in IE8 mode and page message get rendered properly in IE9 also.
Apexpages.currentPage().getHeaders().put('X-UA-Compatible', 'IE=8');
Thanks

Mar 7, 2011

How to Send More than 10 E-mails


Hi All,


This is about how to send more than 10 E-mails. As we know we have a governor limit of sending 10 emails in a process so this is a workaround to send more than E-mails. We can do this by using batch class.


Lets say we have to send all System Administrators details of case logged by them today in a particular format. If suppose we have 15 System Administrators in our organisation, all of them logged 2-3 cases in a day and in the end of the day we want to send the details of case logged only by them in an Email. So here is the code :

global class Batch_CaseEmail implements Database.Batchable<sObject>,Database.Stateful
{
   Map<Id , List<Case>> userCaseMap {get; set;}
   List<Case> allCaseLoggedToday {get; set;}
   
   global Batch_CaseEmail()
   {
       //Map to maintain user id and cases logged by them today
       userCaseMap = new Map<Id, List<Case>>() ;
       
       //All sales rep (System admins)
       List<User> salesRep = new List<User>() ;
       salesRep = [select id , name , Email , ManagerId from User where Profile.Name = 'System Administrator'] ;
       
       //All sales rep ids
       List<Id> salesIds = new List<Id>() ;
       for(User ur : salesRep)
       {
           salesIds.add(ur.Id) ;
       }
      
       //All cases logged today by sales rep
       allCaseLoggedToday = new List<Case>() ;
       allCaseLoggedToday = [select Id, CaseNumber,CreatedById, Owner.name , account.Name , contact.name from Case where CreatedDate = TODAY AND CreatedById in : salesIds] ;
   }

   global Database.QueryLocator start(Database.BatchableContext BC)
   {
      //Creating map of user id with cases logged today by them
      for(Case c : allCaseLoggedToday)
      {
          if(userCaseMap.containsKey(c.CreatedById))
          {
              //Fetch the list of case and add the new case in it
              List<Case> tempList = userCaseMap.get(c.CreatedById) ;
              tempList.add(c);
              //Putting the refreshed case list in map
              userCaseMap.put(c.CreatedById , tempList) ;
          }
          else
          {
              //Creating a list of case and outting it in map
              userCaseMap.put(c.CreatedById , new List<Case>{c}) ;
          }
      }

      //Batch on all system admins (sales rep)
      String query = 'select id , name , Email from User where Profile.Name = \'System Administrator\'';
      return Database.getQueryLocator(query);
   }

   global void execute(Database.BatchableContext BC, List<sObject> scope)
   {
       
      for(Sobject s : scope)
      {
          //Type cast sObject in user object
          User ur = (User)s ;
          
          //If system admin has logged any case today then only mail will be sent
          if(userCaseMap.containsKey(ur.Id))
          {
              //Fetching all cases logged by sys admin
              List<Case> allCasesOfSalesRep = userCaseMap.get(ur.Id) ;
              
              String body = '' ;
              //Creating tabular format for the case details
              body = BodyFormat(allCasesOfSalesRep) ;
              
              //Sending Mail
              Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage() ;
              
              //Setting user email in to address
              String[] toAddresses = new String[] {ur.Email} ;
              
              // Assign the addresses for the To and CC lists to the mail object
              mail.setToAddresses(toAddresses) ;
    
              //Email subject to be changed
              mail.setSubject('New Case Logged');
              
              //Body of email
              mail.setHtmlBody('Hi ' + ur.Name + ',<br/><br/> Details of Cases logged today is as follows : <br/><br/>' + body + '<br/> Thanks');
        
              //Sending the email
              Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
          }
      }
   }
   
   public String BodyFormat(List<Case> lst)
   {
       String str = '' ;
       for(Case cs : lst)
       {
           str += '<tr><td>'+ cs.CaseNumber +'</td>'+'<td>'+ cs.Owner.Name +'</td>'+'<td>'+ cs.Account.Name +'</td>'+'<td>'+ cs.Contact.Name +'</td>'+'</tr>' ;
       }
       str = str.replace('null' , '') ;
       String finalStr = '' ;
       finalStr = '<table border="1"> <td> CaseNumber </td> <td> Owner </td> <td> Account </td> <td> Contact </td> '+ str +'</table>' ;
       return finalStr ;
   }

   global void finish(Database.BatchableContext BC)
   {
   }

}


Now to execute this batch class we can schedule it or simply run this code in system logs for testing :

Batch_CaseEmail controller = new Batch_CaseEmail() ;
Integer batchSize = 1;
database.executebatch(controller , batchSize);



So when we execute it all system administrators will get E-mails in this format 






Thanks.

Mar 5, 2011

Error : "Trigger must be associated with a job detail"

Hi All,


While scheduling a class we some times gets error "Trigger must be associated with a job detail".


For example: I was facing this error when I schedule my class "ScheduleClass" using System.schedule, giving name to the schedule job "One Time ".


ScheduledClass SC = new ScheduledClass() ;
String sch = '0 0 10 * * ?';
System.schedule('One Time ', sch, SC);


Now please notice there is a space after "One Time ", when I removed this extra space from the name ("One Time") my class was scheduled as expected.


Thanks

Feb 26, 2011

Using Field Set on Visual Force Page

This is about how we can use Field Set. We can dynamically bind fields on our visual force page using Field Set. It is very useful when we are working with managed package.

A field set is a grouping of fields. For example we can have a field set that contains fields "Name , Email , Phone , Mobile". If the page is added to a managed package, administrator can add, remove, or reorder fields in a field set to modify the fields presented on visual force page without modifying any code. Creating a field set : Go to Setup > App Setup > Create > Objects > Select your object > Field Set (Beta) > New : 



Fields in "In the Field Set" section is displayed on visual force page and administrator can add more fields in "In the Field Set" from "Available for the Field Set" section.

Visual Force Page Code :



    
        
            
                
            
        
    



Now it will show three fields (Name, Email, Mobile) on visual force page, if we add "Phone" field from "Available for the Field Set" section to "In the Field Set" section then four fields (Name, Email, Mobile, Phone) will be displayed on visual force without changing the code.


Thanks