Trigger:
- The trigger is just a code whenever a database operation is happens that executes automatically before or after DML.
- Trigger used to do automation that cannot be done by using point and click tool.
- Triggers are always created on a particular object.
- Triggers are by default active when you create.
Trigger Types:
Before:
- Trigger that executes before data is saved to the database.
- Usages: Data validation, Data processing, presaving actions.
After:
- After trigger executes after the database operation happens.
- It is used to access the field values that are set by the system such as Ids, and to make changes in other records.
- The record that fire the after trigger are read only.
- Usage: Any type of process actions(approval submission), sending an email,
Trigger Structure :
Trigger < TriggerName > on < Object Name > (Trigger Events)
{
Code Block
}
Trigger Events :
Before insert, Before update, Before delete, After Insert, After update, After delete, After Undelete,
Trigger Context Variable:
This is a variable that gives the value to developer during a trigger runtime process.
These variables are contained in the System.Trigger Class.
IsExecuting ==> Return a true /false if a trigger is running or not.
isinsert ==> Return true if insertion operation occur.
isupdate ==> Return true if updation operation occur.
Isdelete ==> Return true if delete action occur.
isundelete ==> Return true if data was restored from recycle bin.
isbefore ==> Return true before saving the data to the database.
isAfter ==> Return true if the trigger fired after the data saved into the database.
new ==> Return the list of new version of the sObject records.
new map ==> Returns Map< id, sObject > data of all the new record that are created.
Old ==> Return the list of old version of the sObject records.
Old map ==> Return Map< id, sObject > data of all the old version of Sobject record.
trigger accounttrigger on account(before insert)
{
for (account acc = Trigger.new) //Trigger.new is used to get the records.
{
acc.description = 'Test Trigger Description';
}
}
//Call Apex Methods through triggers >> best practise
trigger accounttrigger on account(before insert){
if(trigger.isinsert)
{
AccountTriggerHandler.beforeinsert(Trigger.new);
}
}
public class AccountTriggerHandler{
public static void beforeinsert(List<Account> New List) //Trigger.new will be received in this list
{
for(account acc : Trigger.new)
{
acc.description='Test Trigger Description';
}
}
}
Scenerio
If any user updates the contact record I want to send an email.
Trigger sendemailcontactupdate on Contact (after insert, after update) {
if(trigger.isafter && trigger.isUpdate)
{
TriggerSendEmailToContactHelperClass.sendemailUpdatecontact('Pradhumn sharma');
}
/*
* if(trigger.isafter && trigger.isUpdate){
TriggerSendEmailToContactHelperClass.sendemailUpdate('Pradhumn sharma');
} */
// create a new mail
/* Messaging.SingleEmailMessage M1 = new Messaging.SingleEmailMessage();
// List<String> sendTo = new List<String>();
// sendTo.add(myContact.Email);
// mail.setToAddresses(sendTo);
List<String> Toaddress= new List<String> {'pradhumn.bittu@gmail.com'};
M1.setToAddresses(Toaddress);
M1.setSubject('contact phone number is updated');
M1.setPlainTextBody('Update about your contact');
List<Messaging.Email> se = new List<Messaging.Email>{M1};
System.debug('se');
Messaging.sendEmail(se);
*/
//Trigger ==> Trigger not contain business logic ==>
//Trigger handler
//Trigger helper
//Trigger handler and helper are apex classes (we write the business logic)
}
public class TriggerSendEmailToContactHelperClass {
public static void sendemailUpdatecontact(String Name){
Messaging.SingleEmailMessage M1 = new Messaging.SingleEmailMessage();
List<String> Toaddress= new List<String> {'pradhumn.bittu@gmail.com'};
M1.setToAddresses(Toaddress);
M1.setSubject('Hi' + Name +' contact phone number is inserted');
M1.setPlainTextBody('Update about your contact');
List<Messaging.Email> se = new List<Messaging.Email>{M1};
System.debug('se');
Messaging.sendEmail(se);
}
}
In the trigger so what ever i am doing wheather i am updating or modyfying it how will i know a update , insert is happen what is status of that record who is going to tell me so their we have a concept of trigger context variables.
The record which initiated the database operations is read-only in the after triggers you cannot modify any field value in the after trigger if that record initiated the execution of the particular trigger.
Examples
1.Set shipping field the same as billing when we insert record
trigger billing on account(before insert){
//context variable : Values which developer needs to write the logic.
Trigger.new --> is basically a list that has been defined. It is list of records that are getting inserted.
in the before insert the id will not be generated it is only generted in the after insert.
//if the trigger is getting called on before event then go to this block.
if(trigger.isbefore && trigger.isinsert){
for(account accRec : Trigger.new)
{
if(accRec.shippingcity==null)
//System.debug('accRec' + AccRec);
accRec.shippingcity = accRec=billingcity;
if(accRec.shippingcountry==null)
accRec.shippingcountry = accRec=billingcountry;
if(accRec.shippingpostalcode==null)
accRec.shippingpostalcode = accRec=billingpostalcode;
if(accRec.shippingstreet==null)
accRec.shippingstreet = accRec=billingstreet;
}
}
}
2.While user creating an account if annual revenue provided by the user is less than 1000, then write a logic to throw an error.
Trigger annualrevenue on account(before insert){
if(trigger.isbefore && trigger.isinsert)
{
for(account accRec : Trigger.new)
{
if(accRec.annualrevenue == Null && accRec.annualrevenue <=1000)
accRec.adderror('Anuual Revenue can't be less than 1000');
}
}
}
3.When user create an account write a logic to create a contact with the same name and associate account and contact.
Trigger createcontactwrttoaccount on account (after insert)
{
if(trigger.isafter && trigger.isinsert){
List<contact> ConListToInsert = new List<contact>();
for( account accRec : Trigger.new) //EACH RECORD THAT ARE INSERTED ARE IN ACCREC.
{
contact con = new contact(); //create the instance of the contact
con.lastname = accRec.Name;
//make account the parent of this contact
con.Accountid = acc.id;
ConlistToInsert.add(con); //add that contact in list
}
if(ConListToInsert.size()>0)
Insert ConListToInsert;
}
}
4.When user updates account record if user changes account name throw an error "account name once created cannot be modified".
//how will you know that account name is changed
//Trigger.new ==> Stores the new records
//Trigger.old ==> Stores the old values of the same record
//Trigger.newmap ==> Stores the new records(id is the key,RecordWithNewValues)
//Trigger.oldmap ==> Stores the values of old records(id is the key,RecordWithOldValues)
Trigger oncecreated on Account(before update){
if(trigger.isbefore && trigger.isupdate)
{
for(account accRecNew : trigger.new) //will store the list of new records
{account accRecOld = trigger.oldmap.get(accRecNew.Id); //will store the list of old values and get operator are used to get the values.
if(accRecNew.name!= accRecOld.name) //in get operator we need to provide the key value
{ //we can use the record id of the new record value.
accRecNew.adderror('account cant be modified once created');
}
}
}
}
5.On user updating account record if billing address is changed update all its child contacts mail address field same as the account billing address ?
Trigger updatebillingonaccount on account (after update)
{
if(trigger.isafter && trigger.isupdate){
set<Id> accIdwhichgotbillingaddresschanged = new set<Id> //bulkification // this capture the account id for which the billingcity address is changed
for( account accRecnew : Trigger.new) //EACH RECORD THAT ARE INSERTED ARE IN ACCREC.
{
account accRecOld = trigger.oldmap.get(accRecnew.id);
if(accRecNew.billingcity!=accRecOld.billingcity)
{
accIdwhichgotbillingaddresschanged.add(accRecNew.Id); //by using add you can add your account id into this set
//if billingcity is changed then we are going to store the list into the accIdwhichgotbillingaddresschanged set
//This set will have accountid which got billing address changed
//now querying on contacts
List<account> accwithcontacts = [Select id, name,billingcity,billingstreet (select id , name from contacts) from Account where ID in : accIdwhichgotbillingaddresschanged];
// we need to get only the address where billing address is changed
//need to create the list where we need to add our contacts
List<contact> contactListToupdate = new List <contact>(); //empty list
//we need to run the loop to update the contacts
for(Account acc: accwithcontacts)
{
// so we need to get the all the contacts // we will put all the contact in the list first.
List<contact> contactOfTheLoopedAccount = acc.contact; //acc.name , acc.billingcity will get information of these
//acc.contact will get the information of the contacts by this it will return the list of contacts that are associated with
//this account and in this list list (contactOfTheLoopedAccount) we need to loop it again and finally update the billingcity into
the mailig city.
for (contact con : contactOfTheLoopedAccount)
{
con.mailingcity = acc.billingcity;
con.mailingstreet = acc.billingstreet;
contactListToupdate.add(con);
}
}
} if(contactListToupdate.size()>0){
update contactListToupdate;
}
}
}
6. An Active Account should not be deleted
Trigger activeaccount on Account(before delete)
{
if(trigger.isbefore && trigger.isdelete)
{
for(account accold : trigger.old){
if(accold.Active__c=='yes')
accold.adderror('you can't delete this account');
}
}
}
7.When user deletes an account send an confirmation email to user.
Trigger deleteanacount on Account(After delete)
{
if(trigger.isafter && trigger.isdelete)
{
//trigger.new is not available in the delete operation (new and newmap)
//trigger.old & oldmap are available in the delete operation
List<Messaging.SingleEmailMessage> EmailObjs = new List <Messaging.SingleEmailMessage>();
for(account accold : trigger.old)
{
//create a EmailSingleMessage instance
Messaging.SingleEmailMessage EMailObj = new Messaging.SingleEmailMessage();
List<string> emailaddress = new list<string>();
//Now we want to add current user email address into this list
Current email address can be found by the standard method which is called (userInfo.getUserEmail());
emailaddress.add(userInfo.getUserEmail());
EmailObj.toaddress(emailaddress); // toaddress takes email address in the form of list
EmailObj.setSubject('Account has been sucessfully deleted'+accold.Name);
EmailObj.setPlainTextBody('Hello pradhumn Sharma');
//if more than one record is deleted than we need to send more than one email Whenever you want to send an email in bullk need to
//add this email to list
EmailObjs.add(EmailObj); // So this EmailMessage will have multiple email to send messages.
}
Messaging.SendEmail(EmailObjs);
}
}
Things to keep in mind while wrting triggers
- one trigger per object.
- bulkify your trigger.
- Avoid DML Statement and SOQL queries in for loop (Else it will hit governor limits).
- Do not write logics in trigger, use trigger handler instead.
- Avoid Hardcoding Ids.
- Prevent Recursive triggers.
- Use Comments to make your trigger readable.
Interview Questions
What is the Trigger?
- The trigger is just a code whenever a database operation is happening that executes automatically before or after DML.
- Trigger used to do automation that cannot be done by using point and click tool.
- Triggers are always created on a particular object.
- Triggers are by default active when you create.
What is the trigger syntax?
Trigger < Trigger Name > on < object Name > ( Events ){ // code Block }
What are the context variable?
This is a variable that gives the value to developer during a trigger runtime process.
Trigger.isbefore
Trigger.isafter
Trigger.isinsert
Trigger.isupdate
Trigger.isdelete
Trigger.isundelete
Trigger.new
Trigger.newmap
Trigger.old
Trigger.oldmap
Trigger.size
Trigger.IsExecuting
When do we use before trigger?
If we need to update /prepopulate any field on the same record or to fire an error validating the record then go with before triggers.
When to we use after trigger?
Whenever you want to perform the post actions like sending emails, restore the record in that case after trigger will be used.
What do you mean by bulkifying trigger?
A trigger should be able to handle the all the records whenever we upload the records in bulk.
When to use trigger?
The task and requirement that can't be done by using the point and click tool then we need to use the trigger.
How is Trigger. New Different From Trigger.new map?
Trigger.new :
When we want to iterate over the list and specially if the records have not committed to database and if you want to iterate to the all the fields of list and which do not have the id. In that situtation to capture the new information we can use the trigger.new.
Trigger.newMap:
When you have the specific use case where you need to get a specific record field information based on the id.
Conclusion
Triggers are used to perform the automation that are not done by drag and drop tools.