Future method invocation from Apex Trigger

Apex allows you to make calls to and integrate your apex code with external web service. Apex calls to external web services are referred to as callouts.

To make a callout from trigger, the callout must be asynchronously, so that trigger process doesn’t block you from working while you are waiting for external webservice’s response. The asynchronous callout happen in background process and response will received when the external service returns.

Future me

To make a callout  from a trigger, call a class method that execute asynchronously, such method is called as future method and is annotated with @future(callout=true)

 public class FutureCallout {  
     @future(callout=true)  
     public static void triggerCallout() {  
         HttpRequest request = new HttpRequest();  
         String endPoint = 'Your end point URL';  
         request.setEndPoint(endPoint);  
         request.setMethod('GET');  
         HttpResponse response = new HTTP().send(request);  
     }  
 }  

Call triggerCallout() methods from a trigger

 trigger CalloutTrigger on Account (before insert, before update) {  
   CalloutClass.makeCallout();  
 }  

 

Apex Trigger in Salesforce

Apex triggers enable you to perform custom actions before or after events to records in Salesforce such as insert, update or delete.

Type of Triggers – There are 2 types of Triggers.

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record’s Id or LastModifiedDatefield), and to affect changes in other records. The records that fire the after trigger are read-only.

Trigger Context Variables – 

To access the records that caused the trigger to fire, use context variables. For example, Trigger.New contains all the records that were inserted in insert or update triggers. Trigger.Old provides the old version of sObjects before they were updated in update triggers, or a list of deleted sObjects in delete triggers. Triggers can fire when one record is inserted, or when many records are inserted in bulk via the API or Apex. Therefore, context variables, such as Trigger.New, can contain only one record or multiple records. You can iterate over Trigger.New to get each individual sObject.

NOTE- The system saves the records that fired the before trigger after the trigger finishes execution. You can modify the records in the trigger without explicitly calling a DML insert or update operation. If you perform DML statements on those records, you get an error.

Variable Usage
isExecuting Returns true if the current context for the Apex code is a trigger
isInsert Returns true if this trigger was fired due to an insert operation, from the Salesforce user interface, Apex, or the API.
isUpdate Returns true if this trigger was fired due to an update operation, from the Salesforce user interface, Apex, or the API.
isDelete Returns true if this trigger was fired due to a delete operation, from the Salesforce user interface, Apex, or the API.
isBefore Returns true if this trigger was fired before any record was saved.
isAfter Returns true if this trigger was fired after all records were saved.
isUndelete Returns true if this trigger was fired after a record is recovered from the Recycle Bin (that is, after an undelete operation from the Salesforce user interface, Apex, or the API.)
new Returns a list of the new versions of the sObject records.

This sObject list is only available in insert, update, and undelete triggers, and the records can only be modified in before triggers.

newMap A map of IDs to the new versions of the sObject records.

This map is only available in before update, after insert, after update, and after undeletetriggers.

old Returns a list of the old versions of the sObject records.

This sObject list is only available in update and delete triggers.

oldMap A map of IDs to the old versions of the sObject records.

This map is only available in update and delete triggers.

size The total number of records in a trigger invocation, both old and new.

Using Trigger Exception:- Use addError() method to handle error inside trigger. The error message is displayed in the UX and is logged.

Calling addError() in a trigger causes the entire set of operations to roll back, except when bulk DML is called with partial success.

Users are not allowed to delete an Account if they have related Opportunities

 trigger AccountTrigger on Account(before delete) {  
     //Error on deletion of Account having related opportunities  
     for(Account acc :[SELECT Id FROM Account where Id IN (Select AccountId FROM Opportunity) AND Id IN : trigger.old])  
     {  
         Trigger.oldmap.getId(acc.Id).addError(Cannot delete account with related opportunities);  
     }  
 }  

 

How to make a Custom Field Required?

There are three ways to make a custom field required and each has its own set of considerations.

Field level Requirements

This is the most restrictive of requirements and it requires the field to be entered all the time, regardless of how the record is saved (i.e. through an integration, the API, mass upload, or through the User Interface).

On the Page Layout

This option only makes the field required when the specific page layout that you make this field required is accessed. Therefore, you could technically make this required for some users using a particular page layout but not others. Note that this requirement only applies when the record is edited on the User Interface.

Validation Rule Requirement

The simplest validation rule to simply make a custom field required looks like this:
ISBLANK(Enter_Custom_Field_API_Name_Here__c)

Or if the field is a Number or Currency type field use the following syntax
ISNULL(Enter_Custom_Field_API_Name_Here__c)

Note that like the field level setting, this will apply all the time, regardless of where the record is created/updated.

 

View State in Visualforce Salesforce

The view state of a web page is composed of all the data that’s necessary to maintain the state of the controller during server requests(like sending or receiving data). Since the view state contributes to the overall size of your page, performance of a page can depend on efficiently managing the view state.

Note: Since the view state is linked to form data, the View State tab only appears if your page contains an <apex:form> tag.
In addition, the View State tab displays only on pages using custom controllers or controller extensions.

Salesforce allows Visualforce pages to have a maximum view state size of 135 KB.

To minimize your pages’ view state, you can optimize your Apex controller code and remove any superfluous Visualforce components used.

  • If you notice that a large percentage of your view state comes from objects used in controllers or controller extensions, consider refining your SOQL calls to return only data that’s relevant to the Visualforce page.
  • If your view state is affected by a large component tree, try reducing the number of components your page depends on.
  • Use the transient keyword in your Apex controllers for variables that aren’t essential for maintaining state and aren’t necessary during page refreshes.

What is Component Tree in a VF Page ?

Component Tree represents the overall structure of the VF page. Its size is affected by the number of components you have on the page. Generally, fewer components means a smaller component tree, which could result in faster load times.

Before Trigger Vs After Trigger

Before you write a trigger for any requirement, you face problem about whether to write trigger on Before or After event.  How do you decide?

Requirement – On Contact creation wanted to make the field value ‘HasOptedOutOfEmail’ to be checked by default.

To take decision – it really depends what you are trying to do. We need to consider if it can happen/ can be done before data has saved to database(i.e. before trigger). So you can modify the record in Trigger.new without having to call separate Update. This is the best approach if you’re looking to modify data in the records within Trigger.new.

After trigger happen only after data has been written to database. Example you are trying to create a related record, you need the parent record Id created.

Before Trigger :-

  • Updating the records being inserted or updated.
  • Doing something based on a record you’re modifying.
  •  Examples:
    • Setting field values based on some criteria.
    • Sending an apex email based on the record being inserted or updated.

After Trigger :-

  • Updating/creating records that are not being updated or inserted.
  •  Examples:
    • Creating a contact on an account that’s being edited;
    • Changing a lookup value on a related record from the parent being edited.

Answer to above requirement –

 trigger ContactBeforeTrigger on Contact (before insert) {  
   for(Contact con:trigger.new) {  
     con.HasOptedOutOfEmail = true;  
   }  
 }  
 Trigger ContactAfterTrigger on Contact (after insert) {  
   List<Contact> conList = new List<Contact>();  
   for(Contact conInTrigger : trigger.new){  
     Contact c = new Contact(Id = conInTrigger.Id, HasOptedOutOfEmail = true);  
     conList.add(c);    
   }  
   update conList;  
 }  

You can achieve either of the way as above. But its better to follow the Before trigger then to do using After trigger. Decide which one to be better for you ?

Automation tool to use in Salesforce

Salesforce provides multiple tools to automate your organization’s repetitive business processes:   Process Builder, Workflow, and Visual Workflow.

The best automation tool for your needs depends on the type of business process that you’re automating.

What to Do When a Record Has Certain Values

All three automation tools can address this use case: Workflow, Process Builder, and Visual Workflow. Respectively, these tools create workflow rules, processes, and flows.

We recommend starting with Process Builder, especially for business processes that can be simplified to if/then statements. For example:if a case is escalated, then notify the account owner.
Process Builder includes almost all the functionality that’s available in workflow rules, and more. In fact, a single process can do what it would normally take multiple workflow rules to do.

There are only two things that you can do with workflow that you can’t do with processes.
• Configure actions to be executed at multiple intervals.
With a process, you can configure actions to be performed later, but all those actions are performed at the same time. If you need multiple “later”s, use workflow. For example, use multiple time triggers in a workflow rule to email an account manager one month,two weeks, one week, and three days before a related contract expires.
• Send outbound messages without code.
However, you can work around this limitation by calling Apex code from a process.

If the process is too complicated for the Process Builder or requires more advanced functionality, create a flow by using the Cloud Flow Designer.

For example, create a flow to:
• Use complex branching logic (if certain conditions are true, evaluate for further conditions)
Example: First, check whether a case is escalated. If the case is escalated, check the account’s region and route the case accordingly.
• Sort through, iterate over, and operate on several records
Example: After an opportunity is closed and won, calculate the opportunity’s discount. Then apply that discount to all the related opportunity products.

Automation based on User’s input from a UI ?

If you want to build a user interface/screen to collect information to automate a process, Visual Workflow is the tool to be used.

For example, create a flow that walks customer support representatives through a call script. The flow uses information that the representative entered, such as the caller’s name and account number, to create a case that’s assigned to the right person.

Process Builder Visual Workflow Workflow Approval
Complexity Multiple if/then statement Complex A single if/then Statement A single if/then statement
Starts when Record is changed • User clicks button or link
• User accesses custom tab
• Process starts
• Apex is called
Record is changed • User clicks button or link
• Process or flow starts that
includes a “Submit for
Approval” action
• Apex is called
Supports time-based actions Yes Yes Yes
Supports user interaction Yes
Call Apex code Yes Yes
Create records Yes Yes Tasks only Tasks only
Delete records Yes
Launch a flow Yes Yes Yes
Post to Chatter Yes Yes
Send email Yes Yes Yes Yes
Send outbound messages without code Yes
Submit for Approval Yes Yes
Update fields Any related record Any record The record or its parent The record or its parent

What’s the Difference Between Workflow and Visual Workflow?

Workflow
Workflow enables you to set up workflow rules. A workflow rule identifies what kinds of record changes or additions trigger specified workflow actions, such as sending email alerts and updating record fields.
Workflow rules and actions are associated with a specific object (and can cross objects only to update fields on a related master record).

Visual Workflow
Visual Workflow enables you to create flows, which are triggered by users rather than events. Unlike Workflow, which always executes rules and actions behind the scenes, Visual Workflow offers screens for displaying and collecting information from the user running the flow.

Flows aren’t tied to any one object. They can look up, create, update, and delete records for multiple objects.

DML in Apex Salesforce

DML can be perform in two ways in Apex – Using DML statements or Database class methods.

Usinig DML Statements – to insert new record

 //Create the List of sObject to insert  
 List accList = new List();  
 accList.add(new Account(Name='TestAcc1'));  
 accList.add(new Account(Name='TestAcc3'));  
 accList.add(new Account(Name='TestAcc3'));  
 // DML Statement  
 insert accList;  

Using Database class – to insert record

 //Create the List of sObject to insert  
 List accList = new List();  
 accList.add(new Account(Name='TestAcc1'));  
 accList.add(new Account(Name='TestAcc3'));  
 // DML Statement  
 Database.SaveResult[] srList = Database.insert(accList, false);  
 //Iterate through each returned result  
 for(Database.SaveResult sr : srList) {  
     if(sr.isSuccess()) {  
         // Operation was successful, so get the ID of the record that was processed  
         System.debug('Successfully inserted account. Account ID: ' + sr.getId());  
     }  
     else {  
         // Operation failed, so get all errors  
         for(Database.Error err : sr.getErrors()) {  
             System.debug('The following error has occurred.');  
             System.debug(err.getStatusCode() + ': ' + err.getMessage());  
             System.debug('Account fields that affected this error: ' + err.getFields());  
         }  
     }  
 }  

Database Methods :- Apex Database class provides methods that perform DML operations. These Database methods are static and are called using class name(Database).

  • Database.insert()
  • Database.update()
  • Database.delete()
  • Database.upsert()
  • Database.merge()
  • Database.undelete()

Using Database class method , you have an option allOrNone which specify whether to allow for partial record processing if errors are encountered.You can do so by passing an additional second Boolean parameter.

If you specify false for this parameter and if a record fails, the remainder of DML operations can still succeed. This wont throw any exception, instead return a result object array containing the status of each operation and any error occur.

By default this optional parameter is true – means that if at least one sObject failed to processed then all sObject can’t processed

Insert and Update operation return an array of Database.saveResult object.

Database.saveResult[] results = Database.insert(recordList, false);

NOTE- Upsert return Database.upsertResult object and delete returns Database.deleteResult object.

When to use DML Statement or Database class methods :-

Use DML statements if you want any error that occurs during bulk DML processing to be thrown as an Apex exception that immediately interrupts control flow (by using try. . .catch blocks). This behavior is similar to the way exceptions are handled in most database procedural languages.

Use Database class methods if you want to allow partial success of a bulk DML operation—if a record fails, the remainder of the DML operation can still succeed. Your application can then inspect the rejected records and possibly retry the operation. When using this form, you can write code that never throws DML exception errors. Instead, your code can use the appropriate results array to judge success or failure. Note that Database methods also include a syntax that supports thrown exceptions, similar to DML statements.

 Single Vs. Bulk DML :-

DML operations can performed on single sObject or in bulk on a list of sObjects. Performing bulk DML operations is the recommended way because it helps avoid hitting governor limits, such as the DML limit of 150 statements per Apex transaction.

Requirement :- Updating all Contacts Description__c field to a new value if the department field matches a certain value.

Wrong approach :-

 for(Contact badCon : conList) {  
     if (badCon.Department = 'Finance') {  
         badCon.Description__c = 'New description';  
     }  
     // Not a good practice since governor limits might be hit.  
     update badCon;  
 }  

You are looping through all contact and the contact whose department matches to the value, you are updating the contact. The problem here is -If the number of contact with matching criteria is more then 150, the next update throw exception that can’t be caught for exceeding the DML statement limit of 150.

Recommended Approach :-  Bulkify DML

 // List to hold the new contacts to update.  
 List updatedList = new List();  
 for(Contact con : conList) {  
     if (con.Department == 'Finance') {  
         con.Description = 'New description';  
         // Add updated contact sObject to the list.  
         updatedList.add(con);  
     }  
 }  
 // Call update on the list of contacts.  
 // This results in one DML call for the entire list.  
 update updatedList;  

Here you are bulkifies the DML by calling update on a list of contacts and this is only one DML, below the limit 150 DML.

The other governor limit that affects DML operations is the total number of 10,000 rows that can be processed by DML operations in a single transaction.

DML Transaction:- DML operations execute within a transaction. All DML operations in a transaction either complete successfully, or if an error occurs in one operation, the entire transaction is rolled back and no data is committed to the database.

For example, if a trigger or class creates two accounts and updates one contact, and the contact update fails because of a validation rule failure, the entire transaction rolls back and none of the accounts are persisted in Salesforce.

ActionFunction in Visualforce

ActionFunction component provides support for invoking Controller action method directly from JavaScript code using AJAX request. An apex:ActionFunction component must be child of an apex:form component.

ActionFunction component is used hen we want to call a controller method from Javascript.

Where as Apex ActionSupport – which only provide support for invoking controller action methods from other Visualforce components, <apex:actionFunction> defines a new JavaScript function which can then be called from within a block of JavaScript code.

Example of using Action function.

Controller –

 public class AccountActionFunction {  
   public Account acc{get;set;}  
   public boolean showfname{get;set;}  
   public boolean showlname{get;set;}  
   public boolean showWebAddr{get;set;}  
   public AccountActionFunction() {  
     System.debug('###Inside Constructor');  
     acc = new Account();  
     showfname = false;  
     showlname = false;  
     showWebAddr = false;  
   }  
   public PageReference AccountTypeChange() {  
     System.debug('$$$- Inside AccountTypeChange()');  
     if(acc.Account_Type__c == 'Person') {  
       showfname = true;  
       showlname = true;  
     } else if(acc.Account_Type__c == 'Company') {  
       showWebAddr = true;  
     } else {  
       showfname = false;  
       showlname = false;  
       showWebAddr = false;  
     }  
     return null;  
   }  
   public String getAccounts() {  
     System.debug('@@@ insite getAccounts()');  
     return null;  
   }  
 }  

Visualforce Page –

 <apex:page controller="AccountActionFunction" tabStyle="Account" action="{!getAccounts}">  
   <apex:form >  
     <apex:actionFunction name="AccountTypeJS" action="{!AccountTypeChange}" reRender="typePB"/>  
     <apex:pageBlock >  
       <apex:pageBlockSection title="Select Account type for Different fields" columns="2" id="typePB" collapsible="false">  
         <apex:inputField value="{!acc.Account_Type__c}" onchange="AccountTypeJS()"/>  
         <apex:inputField value="{!acc.First_Name__c}" rendered="{!showfname}"/>  
         <apex:inputField value="{!acc.Last_Name__c}" rendered="{!showlname}"/>  
         <apex:inputField value="{!acc.Web_Address__c}" rendered="{!showWebAddr}"/>  
       </apex:pageBlockSection>  
     </apex:pageBlock>  
   </apex:form>  
 </apex:page>  

 

How to get Object name from an Id in Salesforce

Using Schema class methods we can get the Object name from a ID passed to the below piece of code.

Schema Class – Contains method for obtaining Schema describe information.

getGlobalDescribe()
Returns a map of all sObject names (keys) to sObject tokens (values) for the standard and custom objects defined in your organization.

Signature –

public static map<String, Schema.SObjectType>  getGlobalDescribe().

 String obId='00128000002sXve';  
 String apiName = '';  
 String keyCode = obId.subString(0,3);  
 Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();  
 for(Schema.SObjectType objectInstance : gd.values()) {  
   if(objectInstance.getDescribe().getKeyPrefix()==keyCode) {  
     System.debug('@@@ This Id is related to Object : '+ objectInstance.getDescribe().getName());  
     apiName = objectInstance.getDescribe().getName();  
     system.debug('@@@ API Name : '+apiName);  
   }  
 }  

This will work for both Standard object and Custom Object.

The output will be like below –

schema

 

sObject in Salesforce

sObject refers to any object that can be stored in the Force.com database. The sObject data type is used in Apex code that process different type of sObjects.

  1. sObject s = new Account();

You can use casting to assign sObject to any perticular object that hold the instance like below-

    2.  Account acc = (Account) s; // Legal Assignment

But if try like below it will give runtime error –

    3. Contact con = (Contact) s; // Runtime Error

As the s is generic object type but hold the Account variable as in step -1.

sObject variables are initialized to null, but can be assigned a valid object reference with the new operator.

System generated fields, such as Created By or Last Modified Date, cannot be modified. And even formula field values and values for other fields that are read-only for the context user cannot be changed.

Note:- If your organization has enabled person accounts, you have two different kinds of accounts: business accounts and person accounts. If your code creates a new account using name, a business account is created. If your code uses LastName, a person account is created.