Sunday, 26 August 2018

State Management In Batch Apex in Salesforce

State Management In Batch Apex in Salesforce


Each execution of a batch Apex job is considered a discrete transaction. For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter is considered five transactions of 200 records each.

If you specify Database.Stateful in the class definition, you can maintain state across these transactions. This is useful for counting or summarizing records as they're processed. For example, suppose your job processed opportunity records. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed.
If you do not specify Database.Stateful, all member variables in the interface methods are set back to their original values.
The following example summarizes a custom field total__c as the records are processed:

global class SummarizeAccountTotal implements Database.Batchable<sObject>, Database.Stateful{
global final String Query;
global integer Summary;
global SummarizeAccountTotal(String q){Query=q;
Summary = 0;
}

global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC, List<sObject> scope){
for(sObject s : scope){Summary = Integer.valueOf(s.get('total__c'))+Summary;

}
}

global void finish(Database.BatchableContext BC){

}
}

Database.Callouts

Database.Allowscallouts allows us to use a callout in batch Apex.Callouts include HTTP
requests as well as methods defined with the webservice keyword.

How to make webservice callout from scheduler

scenario-1 : if scheduler doesn't depends on Batch or Queueable(depends on future methods)
scenario-2 : If Scheduler depends on Batch
scenario-3 : If Scheduler depends on Queueable

Note :
if we try to make a call from scheduler,we will get the below exception:

system.calloutException: callout form scheduled Apex not supported

Reason : All we know that we cannot schedule a class which contains callout.
The only solution for this is to use @future annotation to enforce(for Normal apex classes)
but we cannot process future methods inside batch.

Scenario -1 :
if scheduler doesn't depends on Batch or queueable

ex :

//Scheduled Apex
public class DemoScheduler1 implements Schedulable{
    public void execute(SchedulableContext sc){
        system.debug('*******Going to call future method ');
        DemoAsynchronousTest.futureMethodCallFromScheduler();
    }
}
//apex class containing future method
public class DemoAsynchronousTest{
    @future
    public static void futureMethodCallFromScheduler(){
        system.debug('******futureMethodCallFromScheduler get called');
    }
   
}

Scenario -2 :
if scheduler depends on Batch

ex :

public class ExampleScheduler implements Schedulable, Database.AllowsCallouts, Database.Batchable<sObject> {
 
    public void execute(SchedulableContext SC) {
      Database.executebatch(new ExampleScheduler());
   }
 
 public Iterable<sObject> start(Database.Batchablecontext BC){
        ExampleHelper.makeWebserviceCallout();
     return null;   
 }

    public void execute(Database.BatchableContext BC, List<sObject> scope){     
    }

  public void finish(Database.BatchableContext info){
       
    }
}

public class ExampleHelper{

  public static void makeWebserviceCallout(){
  HttpRequest req = new HttpRequest();
  req.setEndpoint('http://www.yahoo.com');
  req.setMethod('GET');
  String username = 'myname';
  String password = 'mypwd';
 
  Blob headerValue = Blob.valueOf(username + ':' + password);
  String authorizationHeader = 'BASIC ' +
  EncodingUtil.base64Encode(headerValue);
  req.setHeader('Authorization', authorizationHeader);
   
  // Create a new http object to send the request object
  // A response object is generated as a result of the request 
 
  Http http = new Http();
  HTTPResponse res = http.send(req);
  System.debug(res.getBody());
 }
}

Scenario-3 :
if scheduler depends on queueable

public class ExampleScheduler implements Schedulable{
 
    public void execute(SchedulableContext SC) {
      System.enqueueJob(new ExampleQueueable());
   }
}

public class ExampleQueueable implements Queueable, Database.AllowsCallouts {

    public void execute(QueueableContext context) {
        ExampleHelper.makeWebserviceCallout();
    }
}

or

global class SampleCalloutCls implements Queueable, Schedulable, Database.AllowsCallouts{
    //variable declaration
    private List<Account> accountList ;

//Queueable interface method 
    public void execute(QueueableContext QC){
        // Perform callout here to get the accounts from external system.       
        //Calling batch process if list contains records.
        if(!accountList.isEmpty()){
           Database.executeBatch(new SampleBatchCls(accountList));
        }
    }

//Method to Schedule the current class
   global void execute(SchedulableContext sc) {
      system.enqueueJob(new SampleCalloutCls()); 
   }

 }
//End of class

Thursday, 23 August 2018

Differences between Enterprise and Parter WSDL

Enterprise WSDL
1.Is strongly typed
2.Contains the metadata about all standard and custom fields and objects
3.Can only be used against your Salesforce instance
Partner WSDL
1.Is loosely typed
2.Takes an array of key-value pairs
3.Does not contain metadata about objects and fields
4.Can be used against many Salesforce.com organizations

Wednesday, 22 August 2018

Different messages in visualforce

<apex:messages> :
==================

This component is used to display warning or error message for a specific component.

Note :
it is used to display an error on only a very specific field.it is used to allow the developer to place field specific errors in a specific location.

ex :

<apex:message for="phone" />
<apex:inputText value={!Phone} label="Phone"
id="Phone" />


<apex:messages> :
================
This component display all the error messages.These errors are displayed as a list with no
styling.

ex :
<apex:messages />
<apex:inputText value={!Phone} label="Phone"
id="Phone" />
<apex:inputText value={!DOB} label="DOB"
id="dob" />

<apex:PageMessages> :
======================

This Component provides the salesforce styling for the messages.

it is used to display all of the messages on a page. it will display salesforce generated messages as well as custom messages added to the apex class.

ex :
 <apex:pageMessages />
<apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />

<apex:pageMessage> :
=====================
This component is used to display custom messages with severity error,warning etc
in the VF Page.

it is used to display a single custom message using the salesforce formatting.you can specify the severity and the strength

ex :
<apex:pageMessage summary="This is page message"  severity="warning" strength="3" />
<apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />

Note :

apex:pageMessages shows all of the errors with formatting,apex:pageMessage only shows
the specified message.

Action tags in salesforce

Action tags support for calling action and refresh the field only not visualforce page.

Action Function :
===================
Action Function is used in the visualforce page to call the service side method using javascript and does not add the Ajax Request before calling the Controller method.

ex :
<apex:actionFunction name=”myactionfun”
action=”{!actionFunctionTest}”
reRender=”pgBlock, pbSection” />

Action Support :
================
As the name indicates action support is used to provide the support to the input field where we can not get event either manually or external event.It adds the AJAX request to visualforce Page and then calls the controller method.

<apex:inputText value=”{!dummyString}” >
                      <apex:actionSupport event=”onchange” action=”{!actionSupportTest}”                                     reRender=”pgBlock, pbSection” />
</apex:inputText>

Action Poller :
================
A timer that sends an AJAX request to the server according to a time interval that
you specify.Each request can result in a full or partial page update.

ex :

<apex:actionPoller action=”{!incrementCounter}” reRender=”counter” interval=”15″ enabled = “true” />

Action Region :
===============
Action Region use AJAX functionality to update partial page.

ex :

<apex:page controller="ActionRegionCLS" >
 <apex:pagemessages id="msgs"></apex:pagemessages>
 <apex:form >
  <apex:pageblock id="pb">
   <table>
     <apex:actionRegion >
      <tr>
        <td> <apex:outputLabel value="Enter Account Number"> </apex:outputLabel> </td>
        <td>             
          <apex:inputtext value="{!reqAccNumber}"/>
          <apex:commandButton value="Retrive" action="{!fillRecord}" rerender="pb,msgs"/>
          </td>
       </tr> 
     </apex:actionRegion>
     <tr>
      <td> <apex:outputLabel value="Account Name"> </apex:outputLabel> </td>
      <td>
        <apex:inputField value="{!accObj.Name}"/>
      </td>
     </tr>
     <tr>
     <td> <apex:outputLabel value="Account Type"> </apex:outputLabel> </td>
      <td>  <apex:inputField value="{!accObj.Type}"/> </td>
     </tr>
   </table>
  </apex:pageblock>
 </apex:form>
</apex:page>

public class ActionRegionCLS{
 public String reqAccNumber{get;set;}
 public Account accObj{get;set;}

 public ActionRegionCLS(){
  accObj = new Account();
 }
 public void fillRecord(){
  if(reqAccNumber !=null && reqAccNumber !=''){
    List<Account> accLst = new List<Account>();
    accLst = [select id,Name,AccountNumber,Type,AnnualRevenue from Account where AccountNumber =:reqAccNumber];
    if(accLst !=null && accLst.size()>0){
     accObj = accLst[0];
    }
    else{
 
     ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.Info,' No Records found with this Account Number:'+reqAccNumber);
     ApexPages.addMessage(myMsg);
     accObj  = null;
 
    }
  }
 }

 }

Action status :
===============

A component that displays the status of an AJAX update request.An AJAX request can
either be in progress or complete.

ex :

<apex:actionStatus id="statusSaveTrip" stopText="">
    <apex:facet name="start">
        <div>
            <div class="popupBackground" />
            <div class="PopupPanel">
                <table border="0" width="100%" height="100%">
                    <tr>
                        <td align="center"><b>Please Wait</b></td>
                    </tr>
                    <tr>
                        <td align="center"><img src="{!$Resource.AJAXProgressBar}"/></td>
                    </tr>
                </table>
            </div>
        </div>
    </apex:facet>
</apex:actionStatus>

Note :

1.actionStatus: used to display start and stop statuses of AJAX requests.
2.actionSupport: used to call a second component when an event happens to the first component.
3.actionPoller: similar to actionSupport, but the event is based on a timer instead of a user action.
4.actionFunction: provides support for invoking a controller action from JavaScript code using an AJAX request by defining a new JavaScript function.
5.actionRegion: used to demarcate which parts of the page the server should reprocess.

what is visualforce view state ?

Visualforce pages that contain a form component also contain an encrypted,hidden form field that encapsulates the view state of the page.The view state is automatically created,and as its name
suggests,it holds the state of the page- state that includes the components,field values and controller state.

1.Minimize number of form on a page.Use apex:actionRegion instead of using 2 or more forms.

2.Refine your SOQL to only retrieve the data needed by the page.

3.All Public and private data members present in standard,custom and controller extensions
are saved.
4.The trasient variables are not passed to view state and therefore not saved in view state.

Note :
The transient keyword prevents the data  from being saved into the view state.This should be used for very temporary variables.

Maximum view state size limit is 135KB

Tips on reducing view state size :
===================================

1.Declare a variable as Trasient if possible.
2.Declare variable as static, as it is not saved in view state.
3.if you want to manage your own state, instead of using <apex:form> use HTML<form>
tag instead.
4.Recreate state instead of saving in view state.means if you can use SOQL instead of saving in some object or list,use it.
5.You can also use web service call, Ajax remoting to recreate state instead of saving in object.

Saturday, 18 August 2018

Difference between StandardController and StandardSetController?


ApexPages.StandardController encapsulates just a single Sobject (e.g. Account, Opportunity).

ApexPages.StandardSetController contains a list of records (one or more), and has additional functions to facilitate pagination (moving between pages)
and updating a number of records at once.

For example in test class when we initialize

ApexPages.StandardController

Account objAccount = [SELECT Name FROM Account LIMIT 1];
ApexPages.StandardController standctrl = new ApexPages.StandardController(objAccount );


ApexPages.StandardSetController

List<account> accountList = [SELECT Name FROM Account LIMIT 20];
ApexPages.StandardSetController ssc = new ApexPages.StandardSetController(accountList);

Remote Action in salesforce

Remote action function in salesforce allows user to access any method from any class
through javascript methods, and get the result as a javascript object for further manipulation.

points to remember while implementing remote action function :

1.Remote action method should have @RemoteAction annotation.
2.The method should also be Global and static.

ex :

global with sharing class AccountRemoteActionController {

    public String accountName { get; set; }
    public static Account account { get; set; }
    //Default Constructor..
    public AccountRemoteActionController() {
   
    }
   
    @RemoteAction
    global static Account getAccount(String accountName)
    {
        account = [select id, Name from Account where Name = :accountName LIMIT 1 ];
        return account;
    }
}



<apex:page docType="html-5.0" controller="AccountRemoteActionController"> 
    <apex:form>
         <script type="text/javascript">
    function getAccountJS()
    {
        // get the value and save in variable
    var varAccName=document.getElementById('MyAccountName').value;
     
        // check account name enetered or not
      if(varAccName=='' || varAccName==null)
        {
         alert('Please enter account name');
        }
        else
            {
           AccountRemoteActionController.getAccount( varAccName,function(result,event)
                                                    {
                                                   
                                                    if(event.status)
                                                        {
                 document.getElementById("{!$Component.TheAccontBlock.TheAccountPageBlockSection.TheFirstItem.accID}").innerHTML = result.Id;
                document.getElementById("{!$Component.TheAccontBlock.TheAccountPageBlockSection.TheSecondItem.accName}").innerHTML = result.Name;
                                                                                           
                                                        }
else if(event.type='exception')
    {
    document.getElementById("error-js").innerHTML = event.message;
    }
     else
         {
          document.getElementById("error-js").innerHTML ='No Account Record Found';
         }                                                   
    },{escape:true});
           
            }
    }
    </script>
        Enter Account Name   <input type="text" id="MyAccountName"/>
        <button id="btnGetAccount" onclick="getAccountJS()">Get Account Name           
        </button>
        <div id="error-js">           
        </div>
        <apex:pageBlock id="TheAccontBlock">
        <apex:pageBlockSection id="TheAccountPageBlockSection" columns="2">
            <apex:pageBlockSectionItem id="TheFirstItem">
               <apex:outputText id="accID"></apex:outputText>
            </apex:pageBlockSectionItem>
             <apex:pageBlockSectionItem id="TheSecondItem">
                 <apex:outputText id="accName"></apex:outputText>
            </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form> 
</apex:page>


global with sharing class OpportunityRemoteActionController {
      public Opportunity opp{get;set;}
      public String stageName{get;set;} 

      public OpportunityRemoteActionController() {
         
      }
       
      public List<SelectOption> getOptions() {
          List<SelectOption> options = new List<SelectOption>();
          Schema.DescribeFieldResult fieldResult = Opportunity.StageName.getDescribe();
          List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
          options.add(new SelectOption('--Select--', '--Select--'));
         for( Schema.PicklistEntry f : ple)
         {       
          options.add(new SelectOption(f.getLabel(), f.getValue()));
         } 
         return options;
      }     

      @RemoteAction
      global static List<Opportunity> getOpportunityDetails(String stageNameDet) {       
             List<Opportunity> opp= [select id,Name,Amount,stageName from Opportunity WHERE stageName =: stageNameDet];       
          return opp;
      }

}


<apex:page controller="OpportunityRemoteActionController" >
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
function getStageJS(){
 var oppStage= document.getElementById("{!$Component.theFm.oppStage}").value; 
  OpportunityRemoteActionController.getOpportunityDetails( oppStage,
    function(result, event){   
         var html = '<table with="100%" border="thick solid">';
          html = html + '<caption><b>Opportunity Details</b></caption><tr></tr>';
          html = html + '<tr><th>Opportunity Name</th>';
          html = html + '<th>Amount</th> </tr>';
         if (event.status && event.result) {                 
          for (var prop in event.result) {         
          html = html + '<tr><td>'+event.result[prop].Name+'</td> <td>'+event.result[prop].Amount+'</td></tr> ';
      }     
       html = html + '</table>';   
            $("#opportunityDetails").html(html);
           
      } else {
             alert(event.message);
      }

}, {escape:true});
}
 </script>
   <div align="center" width="550px">
      <apex:form id="theFm">
        <apex:selectList value="{!stageName}" size="1" id="oppStage" onchange="getStageJS()">
         <apex:selectOptions value="{!options}"/>
         </apex:selectList>
      </apex:form>
   </div>
   <br/>
   <br/>
   <div id="opportunityDetails" align="center">
         <!-- Opportunity details is displayed here. -->
   </div>
</apex:page>

Getter and Setter methods in Apex

Getter and setter methods are used to pass data from your visualforce page to your controller and vice versa.

The "get" method is used to pass data from your apex code to your visualforce page.

The set method is used to pass values from your visualforce page to the controller.


ex :

public class simplegetset {
    public String userinput {get;set;}
    public String getuserinput()
    {
        return 'John';
    }
 
    public void setuserinput(String userinput)
    {
        this.userinput = userinput;
    }
}


<apex:page controller="simplegetset" >
    <apex:form>
    <apex:outputlabel value="Enter your name here"/>
       <apex:inputtext value="{!userinput}">
           <apex:actionsupport event="onchange" rerender="display" />
       </apex:inputtext>                 
    <apex:outputpanel id="display">
        <apex:outputtext value="The name entered is {!userinput}"/>
    </apex:outputpanel>                 
  </apex:form>
</apex:page>


Visualforce requires a "getter" and "setter" to reference a variable in the controller or extension. Without a getter or setter, even public or global variables cannot be referenced in Visualforce expressions.

"get;" is basically: public *datatype* getVarName() { return varName; }

"set;" is basically: public void setVarName(*datatype* value) { varName = value; }

Wednesday, 15 August 2018

what is the Recursive trigger and how to handle it?

Trigger when called over and over then its called recursive trigger.Below error will be display
if not controlled.

error message : maximum trigger depth exceeded

ex : Recursive code

Trigger AccountTrigger on Account(before insert)
{
    insert new Account(Name='test');

}

How to stop it ?

In order to avoid the situation of the recursive call,make sure your trigger is getting executed only one time.To do so, you can create a class with a static Boolean variable with default value true.

In the trigger,before executing your code keep a check that the variable is true or not.once you check,make a variable false.

ex :

public class checkRecursive
{

  private static boolean run=true;

  public static boolean runOnce()
  {
     if(run){
         run=false;
        return true;
      }
      else
       {
         return run;
       }

  }

}

Trigger AccountTrigger on Account(before insert)
{

    if(checkRecursive.runonce())
      {
        insert new Account(Name='test');
      }

}

After executing workflow rules again before trigger and after triggers will execute,how can you avoid?

class :
==========

global class validator_cls
{

 private static boolean blnAlreadyDone=false;

 public static boolean hasAlreadyDone()
  {
     return blnAlreadyDone;
  }

 public static boolean hasAlreadyDone()
  {
     blnAlreadyDone=true;
  }


}

Class :
============


public class AccountTriggerHandler
{

 public void OnBeforeInsert(Account[] newaccounts)
 {
   if(!validator_cls.hasAlreayDone)
     {

        AddUpdateFields(newAccounts);
        validator_cls.setAlreadyDone();
     }

 }


}

Trigger :
==============

Trigger AccountTrigger on Account(before insert,after insert,before update,after update)
{

AccountTriggerHandler handler=new AccountTriggerHandler();

/* Before Insert */

 if(Trigger.isBefore && Trigger.isInsert)
  {
    handler.OnBeforeInsert(Trigger.new);
  }
/* After Insert */
  else if(Trigger.isAfter && Trigger.isInsert)
  {
     handler.onAfterInsert(Trigger.new);
  }
/* Before Update */
  else if(Trigger.isBefore && Trigger.isUpdate)
  {
    handler.onBeforeUpdate(Trigger.old,Trigger.new,Trigger.newMap);
  }
/* After Update */
  else if(Trigger.isAfter && Trigger.isUpdate)
  {
    handler.onAfterUpdate(Trigger.old,Trigger.new,Trigger.newmap);
  }
/* Before Delete */
  else if(Trigger.isBefore && Trigger.isDelete)
  {
    handler.onBeforeDelete(Trigger.old,Trigger.oldmap);
  }
/* After Delete */
  else if(Trigger.isAfter && Trigger.isDelete)
  {
    handler.OnAfterDelete(Trigger.old,Trigger.oldmap);
  }
  else if(Trigger.isUnDelete)
  {
    handler.onUndelete(Trigger.new);
  }

}

Roll up summary functionality through trigger

public class SampleRollupSummary {
 
    public static void rollupContacts(list<contact> lstOfconts){
        system.debug('==lstOfconts== : '+lstOfconts);
        set<id> accIds = new set<id>();
        list<account> updLstOfAccs = new list<account>();
        list<contact> lstCons = new list<contact>();
     
        for(contact con : lstOfconts){
            accIds.add(con.accountid);
        }
        system.debug('==accIds==:'+accIds);
        list<account> lstAccs = [select id,name,Total_Count__c, (select id from contacts) from account where id in : accIds];
     
        for(account acc : lstAccs){
            system.debug('==acc.contacts.size()=='+acc.contacts.size());
            acc.Total_Count__c = acc.contacts.size();
            updLstOfAccs.add(acc);
        }
        if(updLstOfAccs.size() > 0){
            update updLstOfAccs;
        }     
     
    }
 
}


trigger RollupSummaryTriggerOnAccountObj on contact(after insert, after update, after delete, after undelete) {
    if (trigger.isAfter && (trigger.isInsert || trigger.isUpdate || trigger.isUndelete)) {
        SampleRollupSummary.rollupContacts(trigger.new);
    }
    else if (trigger.isAfter && trigger.isDelete) {
        SampleRollupSummary.rollupContacts(trigger.old);
    }
}

Salesforce Governer Limits

1.DML Governing Limits

we can have only 150 DML statements with in a transaction.

we rectify this type of errors by using bulky operations. put similar operation on the object in list and invoke the DML on the list.

2.SOQL Governing Limits

with in a transaction we can write only 100 SOQL queries.

use
Map<Id,Account> accMap=new map<Id,Account>([select id,Name from Account]);

3.DML rows Limit :

Number of DML rows : 10000

4.SOSL Governing Limits :

Number of SOSL queries : 20

5.Maximum CPU time : 10000
6.Maximum heap size : 6000000
7.Number of callouts : 100
8.Number of Email Invocation : 10
9.Number of future calls : 50
10.Number of queueable jobs added to the queue:50
11.Number of mobile apex push calls :10
12.Number of query rows : 50000

DML statements vs Database class Methods


Apex offers two ways to perform DML operations

1.Using DML statements
2.Database class methods

Difference between the two options that by using the Database class method.

You can specify whether or not to allow for partial record processing if errors are encountered.

you can do so by passing an additional second Boolean parameters.

if you specify FALSE for this parameter and if a record fails,the remainder of DML
operations can still succeed.

 ex : Database.insert(accList,false);

False : partial processing allowed
True  : partial processing not allowed

By default this optional parameter is true,which means that if at least one sObject can't be processed,all remaining sObjects won't and an exception will be thrown for the record that causes a failure.

Order of execution of apex code

1. Before triggers:
     If we update child records in before triggers then parent record automatically update.
2. Validation rules:
 If validation matches the criteria then error will populate in same page.
Runs most system validation steps again, such as verifying that all required fields have a non-null value, and runs any user-defined validation rules. The only system validation that Salesforce does not run a second time (when the request comes from a standard UI edit page) is the enforcement of layout-specific rules.
*Note: Saves the record to the database, but does not commit yet.

3. After Triggers:
4. Assignment Rules:
5. Auto Response Rules:
6. Workflow Rules:
If there are workflow field updates, updates the record again.
7. Escalation Rules:
       If the record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record. Parent record goes through save procedure.
     If the parent record is updated, and a grand-parent record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record. Grand-parent record goes through save procedure.
Executes Criteria Based Sharing evaluation.
Commits all DML operations to the database.

8.Executes post-commit logic, such as sending emails



simple steps:
==============
Order of Events
  1. Original record is loaded or new record is initialized
  2. Fields values are loaded into sObjects
  3. System validations rules are executed:
  4. Before triggers are executed
  5. System validations rules are run again and custom validation rules are checked.
  6. Duplicate rules are executed
  7. Record is saved but not committed
  8. After triggers are executed
  9. Assignment rules are executed
  10. Auto-response rules are executed
  11. Workflow rules are executed
  12. Before triggers,system validation rules and after triggers are executed due to workflow field updates
  13. Processes are executed
  14. Escalation rules are executed
  15. Entitlement rules are executed
  16. Rull-up summary fields and cross-object formula fields are updated
  17. Updated parent and grand parent records are saved
  18. Criteria based sharing rules are evaluated
  19. DML operations are committed to the database
  20. Post-commit logic is executed

Apex Basics

Apex is a strongly typed,object -oriented programming language that allows developers
to execute flow and transaction control statements on the Force.com platform.

Apex enables developers to add business logic to most system events,including button clicks,
related record updates and visualforce pages.

Data Types :
============
1.primitives
2.sObjects
3.Collections

Apex primitive data types include :

1.Boolean : can only be assigned true,false or null
2.Decimal : A number that includes a decimal points.
3.Double : A 64-bit number that includes a decimal point
4.ID : Any Valid salesforce.com ID
5.Integer : A 32bit number that does not include a decimal point.
6.Long : A 64-bit number that does not include a decimal point.
7.String : Any set of characters surrounded by single quotes.
8.Date : A value that indicates a particular day.
9.DateTime : A value that indicates a particular day and time
10.Time : A value that indicates a particular time.

sObjects :
=============
the term sObject refers to any object that can be stored in the Force.com platform database.

An sObject variable represents a row of data and can only be declared in Apex.

ex :
Contact c= new Contact(FirstName='raj';LastName='kiran';
Email ='test@gmail.com');

Account a =new Account(Name='TCS');
insert a;

Account a1=[select Name from Account
where ID='857598jh'];
a1.Name='new  Name';
update a1;

Collection :
============
collection of primitives or sObjects.

A LIST is an ordered collection.so use
list when you wnat to identify list element
based on INDEX NUMBER.
List can contain duplicates.

List<string> colors =new List<string>('red','purple','green');

List<Account> accts=[select Name,Type from Account
where Industry='Energy'];

List<Contact> email_contacts=
[select FirstName,LastName from Contact where
Email!=Null];

1. Set
2. List
3. Map

A set is a collection of unique,unordered elements.it can contain primitive data types or sObjects.

A set is an unordered collection of primitives or sObjects that do not contain any duplicate elements.so use SET if you want to make sure that your collection should not conatin Duplicates.

ex :
Set<String> s = new Set<String>();
Set<String> s = new Set<String>{'Jon', 'Quinton', 'Reid'};

commonly you'll see developers construct a set of IDs from a query,trigger context,etc.
and the use it as part of WHERE clause in their SOQL query.

ex :

Set<ID> ids = new Set<ID>{'0017000000cBlbwAAC','0017000000cBXCWAA4'};
List<Account> accounts = [Select Name From Account Where Id = :ids];


Map :
=====
A MAP is a collection of key-value pairs where each unique key maps to a single value.
Keys can be any primitive data type,while values can be a primitive,sObject,Collection
types or an Apex Object.

Use a map when you want to quickly find something by a key.Each key must be unique
but you can have duplicate values in your MAP.

Map<Integer, String> m = new Map<Integer, String>{5 => 'Jon', 6 => 'Quinton', 1 => 'Reid'};
Map<ID, Set<String>> m = new Map<ID, Set<String>>();
// creates a map where the key is the ID of the record
Map<Id,Account> aMap = new Map<Id, Account>([Select Id, Name From Account LIMIT 2]);


Tuesday, 14 August 2018

Triggers in Salesforce


Trigger is piece of code that is executes before and after record is Insert/update/Deleted from the force.com database.

There are two types of Triggers:

1.Before trigger are used to update or validate record values before they're saved to the
database.

2.After triggers are used to access field values that are set by the system and to effect changes in other records.The records that fire the after trigger are read-only.

syntax:
========

trigger triggerName on ObjectName(trigger_events)
{

  //code_block

}

where trigger_events can be a comma-separated list of one or more of the following events :

before insert
before update
before delete
after insert
after update
after delete
after undelete

ex :
========
check email null or not before insert update
record


trigger CheckEmail on contact(before Insert,before update)
{
   for(Contact c:Trigger.new)
   {
     if(c.Email ==Null)
      {
        c.Email.addError('Please insert Emil ID);
      }
   } 
}

Trigger Context Variables :
=====================
All triggers define implicit variables that allow developers to access run-time context.


Trigger.isInsert : Returns true if this trigger was fired due to an insert operation.

Trigger.isUpdate : Returns true if this trigger was fired due to an update operation

Trigger.isDelete : Returns true if this trigger was fired due to delete operation.

Trigger.isBefore : Returns true if this trigger was fired before any record was saved.

Trigger.isAfter : Returns true if this trigger was fired after all records were saved.

Trigger.isUndelete : Returns true if this trigger was fired after a record is recovered from the
Recycle Bin.

Trigger.new : Returns a list of the new versions of the sObject records.Note that this sObject list
is only available in insert and update triggers,and the records can only be modified
in before triggers.

Trigger.newMap : A map of IDs to the new versions of the sObject records.Note that this map
is only available in before update,after insert and after update triggers.

Trigger.old : Returns a list of the old versions of the sObject records.Note that this sObject
list is only available in update and delete triggers.

Trigger.oldMap : A map of IDs to the old versions of the sObject records.Note that this map
is only available in update and delete triggers.

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

Trigger.isExecuting : Returns true if the current apex code is a trigger.


ex :


trigger Opportunity_trigger on Opportunity(before insert,before update){

  for(Opportunity p : Trigger.new)
  {
    if(Trigger.isInsert && p.amount<10000)
      {
       p.addError("amount is less than 10000');
      }
    else if(Trigger.IsUpdate && p.Amount<20000)
         {
           p.addError('Amount is less than 20000');
         }

  }

}

ex :

  public class trigger_class{
    public static void trigger_method(List<Opportunity> oppt){

        Double Total_amount=0;
      for(Opportunity o : Select Amount from opportunity where createddate=Today()
                               and CreatedById= : UserInfo.getUserID()]){
         
           Total_amount=Total_Amount +o.Amount;
       
           }

        for(Opportunity o1 : oppt){
         
           Total_amount=Total_Amount +o1.Amount;
       
              if(Total_amount>100000)
                {
                  01.addError('you have exceeded your daily limit');
                }
            }

    }

  }


trigger t1 on Opportunity(before Insert){
trigger_class.trigger_method(Trigger.new);
}

Transaction Control using Database savepoint and rollback in Apex

SavePoint and Rollback will help us to maintain transaction for DML statement.

suppose you have written multiple lines of DML statements in a try block,if any error
occurs during DML Operations,the operation will be rolled back to the most recent
save point and the entire tranasction will not be aborted.

ex :

savepoint sp=Database.setsavepoint();

try
{
// create account

Account a=new Account();
a.Name='Test';
insert a;

// create contact

Contact c=new contact();
a.accountid=a.id;
insert c;

}
catch(DMLException exc)
{

Database.rollback(sp);

}

In this example, if any error occurs while inserting the Account ‘a’ or Contact ‘c’, then the entire transaction will be rolled back to SavePoint ‘sp’, as specified in the catch section by Database.