Browsing "Older Posts"

Browsing Category "Salesforce Apex Triggers"
  • Salesforce Apex Map & Map methods with Examples

    salesforcepoint Wednesday, 8 July 2020
    Salesforce Apex Map, Map methods with Examples
    Map is one of the collection type in salesforce apex. In this post we are going to see what are the map methods with some basic examples. First of all Map is a key and value pair i.e each and every value is associates with key. Here key is unique, that means if we put one key,value pair into Map, we should not add same key one more time. If key is already exist in map and once again you are trying to add key with different value then old value override with new value.

    Salesforce Apex Map Syntax:

    Map<dataType, dataType> variabeName ;

    If we don't initialize map and 'trying to put new set of key, value' Or trying to use any map methods on that variable, you will end up with null pointer exception. So we need to initialize map whenever we create map variable.

    Map<dataType, dataType> variabeName = new Map<dataType, dataType>();

    eg: Map<String, String> countryWithCapitalMap =  new Map<String, String>();

    Important Apex Map Methods:

    put( ): By using this method we can new set of key, value pair into map.
    example: countryWithCapitalMap.put('India', 'Delhi'); //here India is key & Delhi is corresponding value for key 'India'.

    containsKey(key): By using this method we can check whether key exist or not in Map. It will return true if key is exist in apex map.
    example: countryWithCapitalMap.containsKey('India') //true

    get(Key): It returns value of corresponding key.
    example:  countryWithCapitalMap.get('India') //reurns 'Delhi'

    isEmpty(): It returns true if Map does not contain any key, value pair.
    example:  countryWithCapitalMap.isEmpty() //false

    size():  It returns number of key, value pairs available in Map.
    example: countryWithCapitalMap.size() // 1

    keySet(): It returns SET of key's available in the map.
    example: countryWithCapitalMap.keySet() //{India}

    values(): It returns LIST of values available in map.
    example: countryWithCapitalMap.values() //{Delhi}

    Task: Create a map to store country as Key and corresponding countries as values.

    Country (Key)
    'United States'
    'India'
    States (Value)
    'California',
    'Colorado',
     'Texas' 
    'Andhra Prdesh',
    'Telangana',
    'Karnataka'

    One country can have multiple states so that we should create Map value as List<string>

    Map<String, List<String>> countryWithStatesMap = new Map<String, List<String>>();

    countryWithStatesMap.put('United States', new List<String>{'California','Colorado','Texas'});
    countryWithStatesMap.put('India', new List<String>{'Andhra Prdesh','Telangana','Karnataka'});

    system.debug('Get countries from countryWithStatesMap ===>'+countryWithStatesMap.keyset());
    // o/p: {India, United States}
    system.debug('Get States of India ===>'+countryWithStatesMap.get('India'));
    // o/p: (Andhra Prdesh, Telangana, Karnataka)
    system.debug('Is Srilanka there in Map ===>'+countryWithStatesMap.containsKey('Srilanka')); 
    // o/p: false
  • What is Recursive Trigger in Salesforce? How can we Avoid Recursive Trigger in Salesfore with Example

    salesforcepoint Tuesday, 21 March 2017

    What is Recursive Trigger in Salesforce?

    Recursive Trigger is a trigger which is called and called itself when some DML operation occurs. Recursion basically occurs when we perform same dml in the apex trigger method (ex: If we perform update operation in update triggers).  Recursion occurs when the trigger code called itself in a infinite loop until system throws error “maximum trigger depth exceeded”.

    Salesforce Recursive Trigger Simple Example:

    Trigger t1 on Contact(after  insert){
      Insert new Contact(Lastname=’Venu’, Phone=12345);
    }


    In above trigger, when we  inserts  new contact record , then the trigger t1 called, as per trigger logic new contact record should be created  and that new record calls again this trigger as it is after insert trigger  and again new record inserted it will be goes on in a loop until system stops. Finally  we will get error “maximum trigger depth exceeded” Like Below.





    How To Avoid Recursive Trigger in Salesforce?

    To avoid Recursive Trigger problem we have to create a public class with static Boolean variable as below.

     class:
    public class AvoidRecursive {
       public static boolean firstRun = true;
    }


    Trigger: 
    trigger TestTrigger on Contact (after insert) {
        if(AvoidRecursive.firstRun)
        {
            AvoidRecursive.firstRun = false;
            insert new Contact(Lastname=’Venu’, Phone=12345);
        }  
    }

    Here first time we set Boolean variable as “TRUE” in class .  In trigger variable is equals to true then it goes to inside loop, performs logic and then variable sets as “FALSE” so next  time it will not run(if variable=false then it will not goes to loop & will not perform logic). So if   Code will try to run second time in same request then it will not run.

  • scenario: Before Delete Trigger in Salesforce

    salesforcepoint
    Before Delete Triggers basically used for preventing the record deletion based on some condition.

    Scenario: Write a Trigger on Account to prevent the record delete, if Annual Revenueis grater than or equals to 50,000. If Annual Revenue is more than fifty thousand it should throw error.

    Trigger:

    trigger DeleteTrigger on Account (Before Delete) {
    If(trigger.isBefore){
       If(Trigger.isDelete){
           for(account a: trigger.old){
               if(a.AnnualRevenue>=50000){
                   a.adderror(' You cant delete if "Annual Revenue is more than 50000" ');
                     }
                 }

            }
       }
    }

    If I try to delete Account Record which has more than 50,000 then it shows Validation Errors While Saving Record(s) like below


  • Difference Between Trigger.new & Trigger.old in All Trigger Events with Example

    salesforcepoint Monday, 20 March 2017

    Trigger.new stores list of new records which are going to be inserted and updated into particular object.  Trigger.old stores list of old records which are updated with new values, which are going to be deleted from database.

    Example: I have created one custom object student and it has Name & Teacher custom fields. and if I try to insert new record what will happen..

    Trigger: I have written trigger to check what would be there in Trigger.new & Trigger.old when trigger event occurs. First of all we have to enable Debug Logs in our Organization, so that only we can check.

    trigger exampl26 on Student__c (Before Insert, After Insert, Before Update, After Update, Before Delete, After Delete, after undelete) {
     If(trigger.isBefore)
       {
           if(trigger.isInsert)
            {
            system.debug('Before Insert Trigger.new is---------- :'+trigger.new);
            system.debug('Before Insert trigger.old is------------ :' +trigger.old);
            }
           if(trigger.isupdate)
            {
            system.debug('Before Update Trigger.new is---------- :'+trigger.new);
            system.debug('Before Update trigger.old is------------ :' +trigger.old);
            }
          if(trigger.isDelete)
            {
            system.debug('Before Delete Trigger.new is---------- :'+trigger.new);
            system.debug('Before Delete trigger.old is------------ :' +trigger.old);
            }
       }
    If(trigger.isafter)
       {
           if(trigger.isInsert)
            {
            system.debug('after Insert Trigger.new is---------- :'+trigger.new);
            system.debug('after Insert trigger.old is------------ :' +trigger.old);
            }
           if(trigger.isupdate)
            {
            system.debug('after Update Trigger.new is---------- :'+trigger.new);
            system.debug('after Update trigger.old is------------ :' +trigger.old);
            }
          if(trigger.isDelete)
            {
            system.debug('after Delete Trigger.new is---------- :'+trigger.new);
            system.debug('after Delete trigger.old is------------ :' +trigger.old);
            }

            if(trigger.isundelete)
            {
            system.debug('after Undeletete Trigger.new is---------- :'+trigger.new);
            system.debug('after Undelete trigger.old is------------ :' +trigger.old);
            }
        }
    }

    Before Insert:

    Trigger.New:  (Student__c:{Id=null, Name=venu, Teacher__c=a0328000000nFUFAA2})
    Trigger.Old: NULL

    After Insert: After record inserted to Database

    Trigger.new: (Student__c:{Id=a0128000017bQrcAAE, Name=venu, Teacher__c=a0328000000nFUFAA2})
    Trigger.old:  NULL

    Before Update: i was trying to updated Student Name Venu to 'Venu Gutta' then

    Trigger.new: (Student__c:{Id=a0128000017bQrcAAE, Name=venu Gutta, Teacher__c=a0328000000nFUFAA2})
    Trigger.old: (Student__c:{Id=a0128000017bQrcAAE, Name=venu, Teacher__c=a0328000000nFUFAA2})

    After Update: 
    Trigger.new: (Student__c:{Id=a0128000017bQrcAAE, Name=venu Gutta, Teacher__c=a0328000000nFUFAA2})
    Trigger.old: (Student__c:{Id=a0128000017bQrcAAE, Name=venu, Teacher__c=a0328000000nFUFAA2})

     if I delete the That Record
    Before Delete: 
    Trigger.new: Null
    Trigger.old:  (Student__c:{Id=a0128000017bQrcAAE, Name=venu Gutta, Teacher__c=a0328000000nFUFAA2})

    After Delete:
    Trigger.new: Null
    Trigger.old:  (Student__c:{Id=a0128000017bQrcAAE, Name=venu Gutta, Teacher__c=a0328000000nFUFAA2})

    if I undelete that record from Recylic bin then:
    After Undelete:
    Trigger.new: (Student__c:{Id=a0128000017bQrcAAE, Name=venu Gutta, Teacher__c=a0328000000nFUFAA2})
    Trigger.old: NULL

    Click Here for Basic example trigger for Difference Between 
    Trigger.New and Trigger.old

    Difference Between Before and After Triggers In Salesforce





  • Trigger Scenario: Whenever New Account Record is created then needs to create associated Contact Record automatically

    salesforcepoint Saturday, 18 March 2017

    Object : Account
    Trigger: After Insert

    Description : When ever new Account record is successfully created  then
         create the corresponding  contact record for the account 
    with 
    account name as contact lastname 
    account phone as contact phone

    Trigger Code:

    trigger accountAfter on Account (after insert) {
        List<Contact> cons=new List<Contact>();
        for(Account a: Trigger.New){
            Contact c=new Contact();
            c.accountid=a.id;
            c.lastname=a.name;
            c.phone=a.phone;
            cons.add(c);
        }
        insert cons;

    }


    Test Class  :

    @isTest
    private class AccountAfter {
    @isTest
        static void testme(){
            Integer count=[select count() from Account];
            Integer size=[select count() from Contact];
            Account a=new Account(Name='Testing',phone='111');
            try{
                insert a;
            }catch(Exception e){
                System.debug(e);
            }
            Integer newCount=[select count() from Account];
            Integer newsize=[select count() from Contact];
            Contact c=[select lastname,phone from Contact where accountid=:a.id];
            System.assertEquals(c.lastname,a.name);
            System.assertEquals(c.phone,a.phone);
        }
    }
  • When To Use Before Triggers & After Triggers in Salesforce

    salesforcepoint Wednesday, 22 February 2017
    Difference Between Before Trigger and After Trigger & When Should we use Before & After Triggers:

    Before Triggers: Before triggers are used to update or validate record values before they’re saved to the database.

    Uses:

    1. When we need to write validation on same object record.
    2. Insert and update operation same object.

    Sample Example: if opportunity amount is less then 10000 then through error.


    Trigger validateOppRecord on opportunity(Before Insert){
                             For(opportunity o: Trigger.new)
                               If(o.amount<10000){
                                   o.addError(‘please Enter opportunity amount more than 5000’);
                                  }

                            }

    After Triggers: 
    After Trigger:  After trigger is used when we perform DML operation on one object record and action will effect on another object record by accessing system fields such as record id and last mododifieddate field .

    USES: Insert/Update on related object, not the same object.
                 Notification email.


    Note: We cannot use After trigger if we want to update same record because after saving, record will be committed to database and record will be locked. The records, which fired with after trigger are read only. so  it causes read only error(System.FinalException: Record is read-only) if we perform operation on same object.

    Sample Example: Automatically create a Contact record when we create new Account Record.

    Trigger autoaccCon on Accout(After Insert){
        List<Contact> conlist = new List<Contact>();
        For(Account acc:Trigger.New){
           Contact con = New Contact();
           con.accountid=acc.id;
           con.lastname = acc.name;
           conlist.add(con);
        }
        insert conlist;
    }

  • Trigger Execution Process in Salesforce| Order Of Trigger Execution

    salesforcepoint Thursday, 9 February 2017

    1) Loads the  record from the database or initializes the record for an upsert statement.
    2) Loads the new record field values from the request and overwrites the old values with new values.

    If the request came from a standard User Interface edit page,  runs system validation to check the record for:
      -Checks whether Required values is present or not at the page layout level and field-definition level
      -checks field formats are valid or not (example:  Email ID format, Phone number format)
    3) All before triggers execution.
    4) Runs most system validation steps again, such as verifying that all required fields have a non-null value, and then runs any custom validation rules. The only system validation that Salesforce doesn’t run a second time (when the request comes from a standard UI edit page) is the enforcement of layout-specific rules.
    5) Saves the record to the database, but doesn’t commit yet to Database.
    6) all after triggers Executed.

    7) Run assignment rules and auto-response rules.
    8) workflow rules Executed.
    9) If there is any workflow field update, updates the record again.
    10) If the record  updated with workflow field update, fires before and after triggers one more time (and only one more time), in addition to standard validations. Custom validation rules are not run again.
    11) escalation rules executed.
    12) If the record contains a roll-up summary field, rollup summary fields are calculated and updated.
    13) Run Criteria Based Sharing evaluation.
    14) Commits all DML operations to the database.
    15) Run post-commit logic, such as sending email.
  • Salesforce Apex Triggers Best Practices

    salesforcepoint
    Salesforce Apex Triggers Best Practices

    Important Salesforce Apex Triggers Best Practices

    1) Write One Trigger per one Object
    You can have n number of triggers on single object, but as apex best practice we should write  logic in handler class. If you write multiple Triggers on single object, we cant control order of execution .


    2) Always write Logic-less Triggers
    Always write logic in apex handler or helper class so that we can reuse it. Create context-specific handler methods in trigger handler class.

    3) Always Bulkify your Code
    your code must work on more than one record at a time.
    Bulkifying Apex code means  we make sure the code properly handles more than one record at a time. The trigger code must be process on multiple  records instead of single record for avoid hitting governor limits.


    4) Always Avoid SOQL Queries and DML statements inside FOR Loops
    This is one of the salesforce apex best practices. Since apex is running under Multi-tenant architecture it strictly enforces some governor limits to control wastage of resource utilization. if we use soql inside for loop, that may causes to hit governor Limits.


    If we write  SOQL query inside for loop that iterates across all object records. Soql query will be executed for each record. An individual Apex request works 100 SOQL queries before exceeding that governor limit. So if the trigger is invoked by a batch of more than 100 records, the governor limit will throw a runtime exception.

    Total number of SOQL queries issued for a single Apex transaction- 100
    Total number of DML statements issued-150


    5) Using Collections, Streamlining Queries, and Efficient For Loops to avoid governors.
    It is important to use Apex Collections(LIST, SET,MAP)  to efficiently query data and store the data in memory. As a good developer you should learn effective usage of Map.



    6)Avoid to Query Large Data Sets
    The total number of records that can be returned by SOQL queries in a request is 50,000. If returning a large set of queries causes you to exceed your heap limit, then Use SOQL  with proper filter conditions(Where conditions) , to avoid 50001 limit error.

    7) Use @future Appropriately
    @Future is used to run processes in a separate thread, at a later time when system resources become available. @Future have Future methods that will runs asynchronously.

    8) Avoid Hard-coding IDs
    Don't hard code IDs into queries or apex code. Rather query on some other data to retrieve the desired rows. Record Id's can change across org's.

    9) Handle recursion
    As triggers gets invoked automatically when dml occurs, there could be scenarios where same trigger logic gets called multiple times. This may cause unnecessary resource consumption (Query, cpu time, dml). So we need to handle such code of scenarios effectively.