Google adds

Trigger IMp

    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 have  to write  event operations into the singe trigger with the if conditions. Example code like below

        if (Trigger.isInsert)

           {
                .....
               ......
           }

      if (Trigger.isUpdate)

              {
                    ........
                    ........
               }

A single Apex Trigger is all you need for one particular object. If you write multiple Triggers on single object, we may don’t know which one will be works first.


2) Always write Logic-less Triggers
Always write logic in apex 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 or DML statements inside FOR Loops
Since apex is running under Multitenent architecture it stricly enforces some time limits. if we use soql inside forloop, that may causes to hit governer 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.



6) 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 in For loop, 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 Hardcoding IDs
Don't hardcode IDs into queries or apex code. Rather query on some other data to retrieve the desired rows.
Motivation for Advice
Record IDs can change - for example between a sandbox and a production environment. If code is not written properly, this will result in faulty code.

Trigger Execution Process in Salesforce| Order Of Trigger Execution


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.

When To Use Before Triggers & After Triggers in Salesforce


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 Scenario: Whenever New Account Record is created then needs to create associated Contact Record automatically

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);
    }
}

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


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

scenario: Before Delete Trigger in Salesforce


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

What is Recursive Trigger in Salesforce? How can we Avoid Recursive Trigger in Salesfore with Example

Recursive Trigger is a trigger which is called and called itself when some DML operation occurs. Recursion occurs when the trigger code called itself in a infinite loop until system throws error "“maximum trigger depth exceeded”.

Salesforce Recursive Trigger 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 will be created  and that new record calls again this trigger and again new record inserted it will be goes on in aloop 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.

Count Contacts
trigger CountOfContact on Contact (after insert, after update, after delete) {
    
    list<account> acc=[select id, number__c, (select id, accountid from contacts) from Account];
    list<account> act=new list<account>();
    for(account aa:acc){
        aa.number__c = aa.contacts.size();
        act.add(aa);
    }
    update act;
}

No comments:

Post a Comment

All Governor Limit

Number of SOQL queries: 100 Number of query rows: 50,000 Number of SOSL queries: 20 Number of DML statements: 150 Number of DML rows: 10,...