Wednesday, November 22, 2017

Data Loader vs Batch Apex

Basically Apex data loader is a desktop tool and it is meant for data migration between two systems. In other words, when you want to move data between SFDC and some other environment, you go with data loader.
Say like you want to take a weekly backup of the account object and store it on your desktop, then you can use data loader.

Batch Apex is meant for processing of bulk data within SFDC. It should be used when you have some logic that you want to apply on large data volumes within SFDC, but has nothing to do with an external environment.
Say like you want to send an email to all users who have not logged in in the past month, you can use batch apex (assuming your user volume is BIG).

1) Data Loader is used to export/insert/update/delete data in your organisation,
anything that a person does manually i,e. prepare a sheet and load the data given by client etc

Its just a tool to interact with your database and do manipulations

Whereas Batch Apex is apex code which will include your custom logic and do the data manipulations in bulk. Via batch apex you can automate the data processing with very strong level of flexibility.

2) Bulk API is as name suggest is an API which allows you to load data in millions within less duration of time using parallel asych processing

Data loader can be configured to use Bulk API when you have data in huge amount!

For More information:

https://developer.salesforce.com/forums/?id=906F000000092wuIAA

https://success.salesforce.com/answers?id=90630000000giHyAAI

https://success.salesforce.com/answers?id=90630000000gjCfAAI

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Data Loader:

Data Loader is a client application for the bulk import or export of data. Use it to insert, update, delete, or export Salesforce records. When importing data, Data Loader reads, extracts, and loads data from comma separated values (CSV) files or from a database connection. When exporting data, it outputs CSV files.

The Data Loader is an easy to use graphical tool that helps you to get your data into Salesforce objects. The Data Loader can also be used to extract data from database objects into any of the destinations mentioned above. You can even use the Data Loader to perform bulk deletions by exporting the ID fields for the data you wish to delete and using that source to specify deletions through the Data Loader.

The Data Loader requires the use of the Force.com API. If your Salesforce edition allows the use of the API (Enterprise, Unlimited and Developer Editions), you can download the Data Loader from the Setup menu, under Administer heading - Data Management.

Please go through some of the links below:

https://developer.salesforce.com/page/Data_Loader

https://help.salesforce.com/apex/HTViewHelpDoc?id=data_loader.htm&language=en

https://help.salesforce.com/apex/HTViewHelpDoc?id=inserting_updating_or_deleting_data.htm&language=en

https://www.youtube.com/watch?v=8azP1kuf9IQ

https://www.youtube.com/watch?v=rjuFthPE3jY

Batch Apex:

Batch Apex is mainly to process the existing salesforce records based on certain criteria.
A Batch class allows you to define a single job that can be broken up into manageable chunks that will be processed separately.

When to use Batch Apex
One example is if you need to make a field update to every Account in your organization. If you have 10,001 Account records in your org, this is impossible without some way of breaking it up. So in the start() method, you define the query you're going to use in this batch context: 'select Id from Account'. Then the execute() method runs, but only receives a relatively short list of records (default 200). Within the execute(), everything runs in its own transactional context, which means almost all of the governor limits only apply to that block. Thus each time execute() is run, you are allowed 150 queries and 50,000 DML rows and so on. When that execute() is complete, a new one is instantiated with the next group of 200 Accounts, with a brand new set of governor limits. Finally the finish() method wraps up any loose ends as necessary, like sending a status email.

Sample Batch Apex
1) Start method is automatically called at the beginning of the apex job. This method will collect record or objects on which the operation should be performed. These record are divided into subtasks & passes those to execute method.

2) Execute Method performs operation which we want to perform on the records fetched from start method.

3) Finish method executes after all batches are processed. Use this method to send confirmation email notifications.

Please go through the below links for more information:

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

https://developer.salesforce.com/docs/atlas.en-us.apex_workbook.meta/apex_workbook/apex_batch_intro.htm

http://www.infallibletechie.com/2013/01/simple-batch-apex-example-in-salesforce.html

http://www.salesforcetutorial.com/what-is-batch-apex/

http://www.salesforcetutorial.com/running-batch-apex-example/

https://www.youtube.com/watch?v=PmvpMakxpm8

http://blog.shivanathd.com/2013/01/how-to-write-batch-class-in.html

http://amitsalesforce.blogspot.com/2016/02/batch-apex-in-salesforce-test-class-for.html

https://www.minddigital.com/how-to-call-batch-apex-by-scheduler-class-within-salesforce/

Friday, November 17, 2017

Using the final Keyword

Using the final Keyword

You can use the final keyword to modify variables.Final variables can only be assigned a value once, either when you declare a variable or inside a constructor. You must assign a value to it in one of these two places.
Static final variables can be changed in static initialization code or where defined.Member final variables can be changed in initialization code blocks, constructors, or with other variable declarations.
To define a constant, mark a variable as both static and final.Non-final static variables are used to communicate state at the class level (such as state between triggers). However, they are not shared across requests.
Methods and classes are final by default. You cannot use the final keyword in the declaration of a class or method. This means they cannot be overridden. Use the virtual keyword if you need to override a method or class.

Thursday, November 16, 2017

Sample Trigger Scenarios of Salesforce

Trigger Scenario 1:

Create “Top X Designation” custom object which is the related list to Opportunity (Look up Relationship). In the Top X Designation object, create the fields
  • Type (Picklist),
  • Document Attached (Checkbox)
Create one field Handoff Attached with pick list type with values are Yes, No on Opportunity Object.
Logic :-  If Type (Top X Designation) = “Contract Flow Down/Handoff”, and “Document Attached” = True then “Handoff Attached” = True, otherwise false.
Code:-
trigger UpdateHandoffAttached on Top_X_Designation__c(after insert, after update,
 after delete) {
 List<Opportunity> listoppUpdate=new List<Opportunity>();
 List<Opportunity> listopp=new List<Opportunity>();
 Set<Id> setOppId=new Set<Id>();
 Set<Id> setOppDelete=new Set<Id>();
 map<id,id> mapDocAttchTrue = new map<id,id>();
 map<id,id> mapDocAttchFalse = new map<id,id>();
 map<id,id> mapDelete = new map<id,id>();
 if(Trigger.isInsert || Trigger.isUpdate){
 for(Top_X_Designation__c ada:Trigger.New){
 if(ada.Document_Attached__c==True && ada.Item_Type__c=='Contract Flow
 Down/Handoff'){
 mapDocAttchTrue.put(ada.Opportunity,ada.id);
 setOppId.add(ada.Opportunity);
 }
 else
 mapDocAttchFalse.put(ada.Opportunity,ada.id);
 setOppId.add(ada.Opportunity);
 }
 }
 if(Trigger.isDelete){
 for(Top_X_Designation__c ada:Trigger.old){
 mapDelete.put(ada.Opportunity,ada.id);
setOppId.add(ada.Opportunity);
 setOppDelete.add(ada.Opportunity);
 }
 }
 listopp = “select id,Handoff_Attached__c from Opportunity where id in: setOppId”;
 if(listopp.size()>0 && listopp !=null){
 for(Opportunity opp:listopp){
 if(mapDocAttchTrue.containskey(opp.id)){
 opp.Handoff_Attached__c='Yes';
 }
 if(mapDocAttchFalse.containskey(opp.id)){
 opp.Handoff_Attached__c='No';
 }
 if(setOppDelete.contains(opp.id)){
 opp.Handoff_Attached__c='';
 }
 listoppUpdate.add(opp);
 }
 }
 if(listoppUpdate.size()>0 && listoppUpdate!=null){
 update listoppUpdate;
 system.debug('LLLLLLLLLLLLLLL'+listoppUpdate);
 }
 }

Trigger Scenario 2:-

The following Trigger will fires when we try to create the account with same name i.e. Preventing the users to create Duplicate Accounts
trigger AccountDuplicateTrigger on Account (before insert, before update)
{
 for(Account a:Trigger.new)
 {
 List<Account> acc=“Select id from Account where Name=:a.Name and Rating=:a.Rating
 “;
 if(acc.size()>0)
 {
 acc.Name.addError('You Cannot Create the Duplicate Account');
 }
 }
 }

Trigger Scenario 3:-

The following trigger updates the field called “Hello” by the value “World” whenever we are creating an account or updating an account record. Create the field called “Hello” on the Account Object (Data Type = Text)
trigger HelloWorld on Account (before insert, before update)
{
 List<Account> accs = Trigger.new;
 MyHelloWorld my= new MyHelloWorld(); //creating instance of apex class
 my.addHelloWorld(accs); // calling method from the apex class
 }
Class:
public class MyHelloWorld
 {
 public void addHelloWorld(List<Account> accs)
 {
 for (Account a:accs)
 {
 if (a.Hello__c != 'World')
 {
 a.Hello__c = 'World';
 }
 }
 }
 }

Trigger Scenario 4:-

The following trigger describes when the leads are inserted into the data base it would add Doctor prefixed for all lead names. This is applicable for both inserting and updating the lead records.
trigger PrefixDoctor on Lead (before insert,before update)
{
 List<Lead> leadList = trigger.new;
 for(Lead l: leadList)
 {
 l.firstname = 'Dr.'+ l.firstname;
 }
 }

Trigger Scenario 5:-

The following trigger adds the Opportunity Owner into the sales team automatically whenever the Opportunity is created.
trigger OppTeam on Opportunity (after insert) {
 List<OpportunityShare> sharesToCreate = new List<OpportunityShare>();
 List<OpportunityTeamMember> oppteam = new List<OpportunityTeamMember
 > ();
 OpportunityShare oshare = new OpportunityShare();
 oshare.OpportunityAccessLevel = 'Edit';
 oshare.OpportunityId = trigger.new”0”.Id;
 oshare.UserOrGroupId = trigger.new”0”.createdbyid;
 sharesToCreate.add(oshare);
 OpportunityTeamMember ot = new OpportunityTeamMember();
 ot.OpportunityId = trigger.new”0”.Id;
 ot.UserId = trigger.new”0”.OwnerId;
 ot.TeamMemberRole = 'Account Manager';
 oppteam.add(ot);
 if(Oppteam!=null && Oppteam.size()>0)
 {
 insert Oppteam;
 }
 if(sharesToCreate!=null && sharesToCreate.size()>0)
 {
 list<Database.SaveResult> sr = Database.insert(sharesToCreate,false);
}
 }

Trigger Scenario 6:-

Create the object called “Books” and create field “Price”(data type is Currency) under this object.
Whenever we enter some amount of money in the Price field and once we click on save
button, the value we entered in the Price field is 10% less than the actual price. This is
applicable for while both inserting and updating records.
trigger DiscountTrigger on Book__c (before insert, before update) {
 List<Book__c> books = Trigger.new;
 PriceDiscount.applyDiscount(books);
 }
  [1]
Class
public class PriceDiscount {
 public static void applyDiscount(List<Book__c> books) {
 for (Book__c b :books){
 b.Price__c *= 0.9;
 }
 }
 }

Trigger Scenario 7:-

The following trigger will prevent the users from deleting the Accounts. This is because System Administrator has all the permissions, we cannot change the permissions.
trigger AccountDelete on Account (before delete) {
 for(Account Acc:trigger.old)
 {
 acc.adderror('You Cannot Delete the Account Record');
 }
 }

Trigger Scenario 8:-

Create Custom field called “Number of Locations” on the Account Object (Data Type=Number)
The following trigger creates the number of contacts which are equal to the number which we will enter in the Number of Locations field on the Account Object
Code:
trigger ContactsCreation on Account (after insert) {
 list<contact> listContact = new list<contact>();
 map<id,decimal> mapAcc=new map<id,decimal>();
 for(Account acc:trigger.new){
 mapAcc.put(acc.id,acc.Number_of_Locations__c);
 }
 if(mapAcc.size()>0 && mapAcc!=null){
 for(Id accId:mapAcc.keyset()){
 for(integer i=0;i<mapAcc.get(accId);i++){
 contact newContact=new contact();
 newContact.accountid=accId;
 newContact.lastname='contact'+i;
 listContact.add(newContact);
 }
 }
 }
 if(listContact.size()>0 && listContact!=null)
 insert listContact;
 }

Trigger Scenario 9:-

Create the object called “Customer Project” and create Status field under this object with picklist data type (Values=Active, Inactive). Create the relationship between this custom object and Opportunity so that Customer Project is related list to the Opportunity.
Create  Active Customer project‑ field on Opportunity object (Data Type=Checkbox)
The logic is when we create Customer Project for an Opportunity with the Status=Active, then Active Customer project check box on the Opportunity Detail page is automatically
checked.
Code:-
trigger UpdateCPActivenOnOppty on Customer_Project__c (after insert)
 {
 List<Opportunity> opps=new List<Opportunity>();
 for(Customer_Project__c cp:Trigger.New){
 if(cp.Status__c=='Active'){
 Opportunity opp= new Opportunity(id=cp.Opportunity__c);
 opp.Active_Customer_Project__c = True;
 opps.add(opp);
 }
 }
 update opps;
 }

Trigger Scenario 10:-

Description:
We have Stakeholder object that is the related list to Opportunity and Contact. On Contact detail page, we have NPS ID field on the Contact detail page that is look up to the Voice of NPS object (Customer Object). The following code will get the NPS ID field value from the Contact detail page in the Stackholders page which we can able to clickable.
Create NPS Id 1 field on the stackholders object which is the look up to the Voice of NPS object (Customer Object)
Note:-
‑ we can also get the NPS Id 1 on the Stakeholder’s page using the formula field but will not able to clickable.
Code Single Record:-
triggerUpdateNPSid on Stakeholder__c (before insert, before update){
 List<id>ConList=new List<id>();
 for(Stakeholder__csh:Trigger.New){
ConList.add(sh.Contact_Name__c);
 }
 List<Contact>lc=“Select NPS_Id__c From Contact Where id IN : ConList”;
 for(Stakeholder__csh:Trigger.New){
 sh.NPS_Id1__c=lc”0”.NPS_Id__c;
 }
 }
Code Bulk Records:-
trigger UpdateNPSid on Stakeholder__c (before insert, before update){
 List<id> ConList=new List<id>();
 map<id,id>map_NPS_Cont = new map<id,id>();
 for(Stakeholder__c sh:Trigger.New)
 {
 if(sh.Contact_Name__c!=null)
 ConList.add(sh.Contact_Name__c);
 }
 List<Contact> lc=“Select Id,NPS_Id__c From Contact Where id IN : ConList”;
 if(lc!=null && lc.size()>0)
 {
 for(Contact c:lc){
 If(c.NPS_Id__c!=null){
 map_NPS_Cont.put(c.Id,c.NPS_Id__c);
 }
 }
 for(Stakeholder__c sh:Trigger.New){
 if(sh.Contact_Name__c!=null)
 sh.NPS_Id1__c = map_NPS_Cont.get(sh.Contact_Name__c);
 else
 sh.NPS_Id1__c = null;
 }
 }
 }

Trigger Scenario 11:-

Create “Sales Rep” field with data type (Text) on the Account Object. When we create the Account record, the Account Owner will be automatically added to Sales Rep field. When we update the Account owner of the record, then also the Sales Rep will be automatically updated.
triggerUpdateSalesRep on Account (Before insert,Before Update){
 Set<Id>setAccOwner=new Set<Id>();
 for(Account Acc: trigger.new)
 {
 setAccOwner.add(Acc.OwnerId);
 }
 Map<Id,User>User_map = new Map<Id,User>(“select Name from User where id
 in:setAccOwner”);
 for(Account Acc: Trigger.new)
 {
 User usr=User_map.get(Acc.OwnerId);
 Acc.sales_Rep1__c=usr.Name;
 }
 }

Trigger Scenario 12:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the related object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Now logic is when we create contact by checking Contact Relationship checkbox, then Contact Relationship will be created automatically for that contact.
Code:
trigger CreateCRonContactCreation on Contact (after insert) {
 if(trigger.isAfter)
 {
 if(trigger.isInsert)
 {
 ContactMasterHandler ConIns = New ContactMasterHandler();
 ConIns.createContactRelationshipByContact(trigger.New);
}
 }
 }
Class:
Public Class ContactMasterHandler {
 public void createContactRelationshipByContact(list<Contact> List_Contacts)
 {
 list<Contact_Relationship__c> ConList= new list<Contact_Relationship__c>();
 for(Contact newconts:List_Contacts)
 {
 if(newconts.Contact_Relationship__c== true)
 {
 Contact_Relationship__c CR = new Contact_Relationship__c();
 CR.Name=newconts.Lastname;
 CR.Contact__c= newconts.id;
 ConList.add(CR);
 }
 }
 insert ConList;
 }

Trigger Scenario 13:-

When we change the Owner of the Contact Relationship, then the Owner name will be automatically populated in the Contact Relationship Name field.
Trigger:
trigger ContactRelationshipMasterTrigger on Contact_Relationship__c(before update)
 {
 if(trigger.isBefore)
 {
 if(trigger.isUpdate)
 {
 //call the handler for the before update trigger event
 updateCROwnerName ConRelUpd = New updateCROwnerName();
 ConRelUpd.updateContactRelationshipNameByOwner(trigger.New);
 }
 }
 }
Class:
Public Class updateCROwnerName{
 public void updateContactRelationshipNameByOwner(list<Contact_Relationship__c> co
 nt_Rel)
 {
 map<Id,Id> map_Id_Own = new map<id,id>();
 map<Id,string> map_id_Name = new map<id,string>();
 set<id> Idset = new set<id>();
 for(Contact_Relationship__c List_recs:cont_Rel)
 {
 Idset.add(List_recs.Ownerid);
 }
 list<user> u=“select id,Name from user where id in:Idset”;
 for(user list_users:u)
 {
 map_id_Name.put(list_users.Id,list_users.Name);
 }
 if(u!=null && u.size()>0)
 {
 for(Contact_Relationship__c List_recs:cont_Rel)
 {
 if (List_recs.Ownerid!=null)
 {
 List_recs.Name = map_id_Name.get(List_recs.Ownerid);
 }
 }
 }
 }
 }

Trigger Scenario 14:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Trigger Scenario 12 logic will says that when we create contact by checking Contact Relationship checkbox, then Contact Relationship will be created automatically for that contact.
No this logic will for when we delete the Contact, Then Contact Relationship will be deleted automatically
 trigger DeleteCRonContactDeletion on Contact (before delete) {
 if(trigger.isBefore)
 {
 if(trigger.isDelete)
for(Contact c:Trigger.old)
 {
 Contact_relationship__c CR=new Contact_relationship__c();
 CR=“Select Id from Contact_Relationship__c where Contact__c IN:GlobalUtility.getUni
 queIds(Trigger.Old)”;
 delete CR;
 }
 }
 }
 }
Global Utility Classs:
public static set<Id> getUniqueIds(list<SObject> sobs)
 {
 set<Id> Ids = new set<Id>();
 for (SObject sob : sobs) {
 Ids.add(sob.Id);
 }
 return Ids;
 }

Trigger Scenario 15:-

Create the field called “Contact Relationship” checkbox on the Contact Object and Create the object called “Contact Relationship” which is related list to the Contacts.(Look Up Relationship).
Trigger Scenario 14 will says that when we delete the Contact, Then Contact Relationship will be deleted automatically
Now the Logic is when we undelete the Contact, then Contact Relationship will be undeleted automatically
Triggser:
trigger UnDeleteCRonContactUnDeletion on Contact (After Undelete) {
 if(trigger.isUndelete)
 {
//call the handler for the after undelete trigger event
 ContactMasterHandler_Undelete ConIns = New ContactMasterHandler_Undelete(
 );
 ConIns.undeleteContactRelationshipsByContact(Trigger.New);
 }
 }
Class
Public Class ContactMasterHandler_Undelete{
 public void undeleteContactRelationshipsByContact(list<Contact> List_Contacts)
 {
 set<Id> ContactIds = New set<Id>();
 if(List_Contacts!=null && List_Contacts.size()>0)
 {
 list<Contact_Relationship__c> List_ConRels= new list<Contact_Relationship__c>(
 );
 List_ConRels= “select id from Contact_Relationship__c where isDeleted=TRUE and Co
 ntact__c in: GlobalUtility.getUniqueIds(List_Contacts)”;
 undelete List_ConRels;
 }
 }
 }

Trigger Scenario 16:-

Create field called “Count of Contacts” on Account Object. When we add the Contacts for that Account then count will populate in the field on Account details page. When we delete the Contacts for that Account, then Count will update automatically.
Inclined towards the profession of the Salesforce? 
Then what is the waiting for.. study the blog post on Salesforce Training to master the skill.
Note:
The above logic will be applicable when we have look up relationship. But When we have the Master – Detail relationship, then we can create Rollup Summary field to get the count of child records using “Count” function.
trigger CountOfContacts on Contact (after insert,after delete) {
 set<id> accid=new set<id>();
 list<contact> contactlist =new list<contact>();
 list<contact> listcon=new list<contact>();
 list<account> acclist=new list<account>();
 list<account> listAcc=new list<account>();
map<id,integer> mapCount=new map<id,integer>();
 if(trigger.isinsert){
 for(contact con:trigger.new){
 accid.add(con.accountid);
 }
 }
 if(trigger.isdelete){
 for(contact con:trigger.old){
 accid.add(con.accountid);
 }
 }
 acclist=“select id,name from account where id in:accid”;
 contactlist = “select id,name,accountid from contact where accountid in:accid”;
 for(account acc:acclist){
 listcon.clear();
 for(contact c:contactlist){
 if(c.accountid==acc.id){
 listcon.add(c);
 mapCount.put(c.accountid,listcon.size());
 }
 }
 }
 if(acclist.size()>0){
 for(Account a:acclist){
 if(mapCount.get(a.id)==null)
 a.Count_Of_Contacts__c=0;
else
 a.Count_Of_Contacts__c=mapCount.get(a.id);
 listAcc.add(a);
 }
 }
 if(listAcc.size()>0)
 update listAcc;
 }

Trigger Scenario 17:-

Create the object called “Customer” and create the Master-Detail Relationship on Customer object so that Customer will be the related list to Account record. Create the field called “Account Manager” on Customer object which is lookup to the user object.
Now Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Code:
trigger InsertAccountTeam on Customer__c (after insert) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isInsert)
 {
 For(Customer__c c:Trigger.new)
 {
 if(c.Account_Manager__c!=null){
 atm = new AccountTeamMember();
 atm.accountid=c.Account__c;
 atm.teamMemberRole='Account Manager';
atm.UserId=c.Account_Manager__c;
 AccountShare shares = new AccountShare();
 shares.AccountId=c.Account__c;
 shares.UserOrGroupId = c.Account_Manager__c;
 shares.AccountAccessLevel='Read/Write';
 shares.OpportunityAccessLevel = 'Read Only';
 shares.CaseAccessLevel='Read Only';
 newShare.add(shares);
 atm_list.add(atm);
 }
 }
 if(atm_list!=null)
 insert atm_list;
 if(newShare!=null && newShare.size()>0)
 List<Database.saveresult> sr=Database.insert(newShare,false);
 }
 }

Trigger Scenario 18:-

The above trigger(Trigger Scenario 17) Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Now the following trigger logic is when we update the user in the “Account Manager”, the Account team will be updated automatically.
Code:
trigger UpdateAccountTeam on Customer__c (before update) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isupdate)
 {
 if(trigger.isbefore)
 {
 Set<Id> setAccIds1=new Set<Id>();
 Set<Id> setDelATM=new Set<Id>();
 Map<id,Set<Id>> mapAccMgrs=new Map<id,Set<Id>>();
 for(Customer__c c:Trigger.new)
 {
 if(trigger.oldmap.get(c.Id).Account_Manager__c!=c.Account_Manager__c
 &&c.Account_Manager__c!=null )
 {
 setAccIds1.add(c.Account__c);
 }
 }
 List<Customer__c> listPLAccMgrs=“select id,Account_Manager__c,Account__c
 from Customer__c where Account__c in:setAccIds1 and id not
 in:trigger.newmap.keyset()”;
 if(listPLAccMgrs!=null && listPLAccMgrs.size()>0)
 {
 for(Customer__c c:listPLAccMgrs)
 {
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(null==idMgrs){
 idMgrs=new set<Id>();
 mapAccMgrs.put(c.Account__c,idMgrs);
 }
 idMgrs.add(c.Account_Manager__c);
 }
 }
 Map<id,List<AccountTeamMember>> mapStdAccTeam=new
 Map<id,List<AccountTeamMember>>();
 List<AccountTeamMember> listStdAcc Team=“select id,UserId,AccountId from
 AccountTeamMember where AccountId in:setAccIds1 “;
 if(listStdAccTeam!=null && listStdAccTeam.size()>0){
 for(AccountTeamMember recAccTeam :listStdAccTeam)
 {
 List<AccountTeamMember>
 listStdAccTeamMap=mapStdAccTeam.get(recAccTeam.AccountId);
 if(null==listStdAccTeamMap){
 listStdAccTeamMap=new List<AccountTeamMember>();
 mapStdAccTeam.put(recAccTeam.AccountId,listStdAccTeamMap);
 }
 listStdAccTeamMap.add(recAccTeam);
 }
 }
 system.debug('***********'+mapAccMgrs);
 for(Customer__c c:Trigger.new)
 {
 if(trigger.oldmap.get(c.Id).Account_Manager__c!=c.Account_Manager__c
 &&c.Account_Manager__c!=null )
 {
 List<AccountTeamMember>
 listAccTeam=mapStdAccTeam.get(c.Account__c);
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(listAccTeam!=null && listAccTeam.size()>0 )
{
 if(idMgrs!=null && idMgrs.size()>0 &&
 !(idMgrs.Contains(trigger.oldmap.get(c.Id).Account_Manager__c)))
 {
 for(AccountTeamMember recATM:listAccTeam)
 {
 if(recATM.UserId==trigger.oldmap.get(c.Id).Account_Manager__c)
 setDelATM.add(recATM.Id);
 }
 }
 else if(idMgrs==null)
 {
 for(AccountTeamMember recATM:listAccTeam)
 setDelATM.add(recATM.Id);
 }
 }
 atm = new
 AccountTeamMember(accountid=c.Account__c,teamMemberRole='Account
 Manager',UserId=c.Account_Manager__c);
 AccountShare shares = new AccountShare();
 shares.AccountId=c.Account__c;
 shares.UserOrGroupId = c.Account_Manager__c;
 shares.AccountAccessLevel='Edit';
 shares.OpportunityAccessLevel = 'None';
 newShare.add(shares);
 atm_list.add(atm);
 }
 }
List<AccountTeamMember> listDelATM=“select id from AccountTeamMember
 where id in:setDelATM”;
 if(listDelATM!=null && listDelATM.size()>0 )
 delete listDelATM;
 if(atm_list!=null)
 insert atm_list;
 if(newShare!=null && newShare.size()>0)
 List<Database.saveresult> sr=Database.insert(newShare,false);
 }
 }

Trigger Scenario 19:-

The trigger scenario 17 Logic is when we create Customer record for account record, then the user in Account Manager field will be automatically added to Account Team of that associated account.
Now the following trigger gives the logic about when we delete the “Customer” of that account, then the user will deleted automatically from the Account Team of that account.
trigger DeleteAccountTeam on Customer__c (before delete) {
 List<AccountTeamMember> atm_list=new List<AccountTeamMember>();
 AccountTeamMember atm = new AccountTeamMember();
 List<AccountShare> newShare = new List<AccountShare>();
 if(trigger.isdelete)
 {
set<id> setAccids = new set<id>();
 Set<Id> setDelATM=new Set<Id>();
 Map<id,Set<Id>> mapAccMgrs=new Map<id,Set<Id>>();
 for(Customer__c c:Trigger.old)
 {
 setAccids.add(c.Account__c);
}
 List<Customer__c> listPLAccMgrs=“select id,Account_Manager__c,Account__c from
 Customer__c where Account__c in:setAccids and id not in:trigger.oldmap.keyset()”;
 if(listPLAccMgrs!=null && listPLAccMgrs.size()>0)
 {
 for(Customer__c c:listPLAccMgrs)
 {
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(null==idMgrs){
 idMgrs=new set<Id>();
 mapAccMgrs.put(c.Account__c,idMgrs);
 }
 idMgrs.add(c.Account_Manager__c);
 }
 }
 Map<id,List<AccountTeamMember>> mapStdAccTeam=new
 Map<id,List<AccountTeamMember>>();
 List<AccountTeamMember> listStdAccTeam=“select id,UserId,AccountId from
 AccountTeamMember where AccountId in:setAccids”;
 if(listStdAccTeam!=null && listStdAccTeam.size()>0){
 for(AccountTeamMember recAccTeam :listStdAccTeam)
 {
 List<AccountTeamMember>
 listStdAccTeamMap=mapStdAccTeam.get(recAccTeam.AccountId);
 if(null==listStdAccTeamMap){
 listStdAccTeamMap=new List<AccountTeamMember>();
 mapStdAccTeam.put(recAccTeam.AccountId,listStdAccTeamMap);
 }
 listStdAccTeamMap.add(recAccTeam);
}
 }
 for(Customer__c c:Trigger.old)
 {
 List<AccountTeamMember>
 listAccTeam=mapStdAccTeam.get(c.Account__c);
 Set<Id> idMgrs=mapAccMgrs.get(c.Account__c);
 if(listAccTeam!=null && listAccTeam.size()>0 )
 {
 if(idMgrs!=null && idMgrs.size()>0 &&
 !(idMgrs.Contains(trigger.oldmap.get(c.Id).Account_Manager__c)))
 {
 for(AccountTeamMember recATM:listAccTeam)
 {
 if(recATM.UserId==trigger.oldmap.get(c.Id).Account_Manager__c)
 setDelATM.add(recATM.Id);
 }
 }
 else if(idMgrs==null)
 {
 for(AccountTeamMember recATM:listAccTeam)
 setDelATM.add(recATM.Id);
 }
 }
 }
 List<AccountTeamMember> listDelATM=“select id from AccountTeamMember
 where id in:setDelATM”;
if(listDelATM!=null && listDelATM.size()>0 )
 delete listDelATM;
 }
 }

Trigger Scenario 20:-

When we create the Opportunity with the Probability=20, then the opportunity owner will be automatically added to Account Team of the associated account for that Opportunity.
Code:
trigger UpdateATMwithOwneronOptyCreate on Opportunity (after insert,after update) {
 List<AccountShare> list_share= new List<AccountShare>();
 List<AccountTeamMember> list_atm=new List<AccountTeamMember>();
 for(Opportunity opp:Trigger.New)
 {
 if(opp.Probability==20)
 {
 AccountTeamMember atm=new AccountTeamMember();
 atm.accountid=opp.accountid;
 atm.teamMemberRole='Account Manager';
 atm.UserId=opp.Ownerid;
 AccountShare share = new AccountShare();
 share.AccountId=opp.Accountid;
 share.UserOrGroupId = opp.OwnerId;
 share.AccountAccessLevel='Read/Write';
 share.OpportunityAccessLevel = 'Read Only';
 share.CaseAccessLevel='Read Only';
 list_atm.add(atm);
 list_share.add(share);
 }
 }
 if(list_atm!=null)
 insert list_atm;
 if(list_share!=null && list_share.size()>0)
 List<Database.saveresult> sr=Database.insert(list_share,false);
Technology:
In the above triggers
  • OpportunityTeamMember is backend name of Sales Team
  • For creation of Account Team we need to create Account Share which will bethere at the backend
  • For creation of Sales team, we need to create Opportunity Share which will be there at the backend
Note: For more clarity, go to the Data Loader and click on the “Export” operation and click on the select “Show all Salesforce Objects” checkbox, then we can able to see Account Share and Opportunity Share.

An Introduction to 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. This 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.
This article provides an introduction to view state, some code samples to show the effect on view state, as well as best practices for optimizing view state in order to improve page performance.

What is View State?

Let's start by understanding the need for view state. In the following illustration, a user requests a web page with a simple form on it, and fills out the form and submits it. If the user's input fails the validation rules for the form, the server responds with an error message - the user corrects the error and resubmits it successfully. Behind the scenes the browser is issuing HTTP requests.
Viewstate2.png
The page is initially retrieved with a GET request and form submissions happen via POST requests. These POST requests are also called postbacks since the data on the form is being posted back to the same page. From the user perspective, this is a stateful interaction since the page state is changing based on its previous state. However HTTP is a stateless protocol, which means that the initial GET and the two subsequent POSTs are treated as independent requests for the page. As a result, some other mechanism is needed to persist state information across HTTP requests.
In Visualforce, page state is persisted as a hidden form field that is automatically inserted into a form when the page gets generated. We call this the view state of the page. The view state captures the state of the page -- state of its associated controllers and extensions and the component tree on the page. The view state is posted back along with the other form data, which gives the server enough information to recreate the page state to which new changes can be applied. Please consult this section in Visualforce documentation to understand the order of execution for a Visualforce page.

What is Contained in the View State?

The data in the view state should be sufficient to recreate the state of the page when the postback is received. To do this, it stores the following data:
  • All non-transient data members in the associated controller (either standard or custom) and the controller extensions.
  • Objects that are reachable from a non-transient data member in a controller or controller extension.
  • The component tree for that page, which represents the page's component structure and the associated state, which are the values applied to those components.
  • A small amount of data for Visualforce to do housekeeping.
View state data is encrypted and cannot be viewed with tools like Firebug. The view state inspector described below lets you look at the contents of view state.

Examining the View State

Developer environments have a view state inspector, which lets you view the contents of the view state. This information can help you in optimizing the view state size. Once enabled, it shows up as a tab in Development Mode, as follows.

Viewer.png

The Visualforce Developer Guide contains details on how to use this tool.

View State in Action

In the previous sections, we looked at what is contained in the view state and how the view state inspector lets you view its contents. To make the concepts around view state a little more concrete, this section looks at a few sample pages and their associated view state.

Sample 1

Here we have a page that uses a standard controller with a single field. The associated view state is shown below.
<apex:page standardController="Account">
    <apex:form >
        <apex:pageBlock title="My Content" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="My Content Section" columns="2">
                <apex:inputField value="{!account.name}"/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Sample1.png

Sample 2

The following listing shows a Visualforce page with a custom controller and a single field. Figure 4 shows the associated view state which contains an account instance since it has been declared as a non transient member variable in our controller. Notice how simple our controller code to update the account is.
<apex:page controller="MyController1" >
     <apex:form >
        <apex:pageBlock title="My Content" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="My Content Section" columns="2">
                <apex:inputField value="{!account.name}"/>              
            </apex:pageBlockSection>
        </apex:pageBlock>
      </apex:form>
</apex:page>

public with sharing class myController1 {
   public final Account account {get; set;}

   public myController1() {
        account = [select name from Account where id   =&nbsp;:ApexPages.currentPage().getParameters().get('id')];
    }
    public PageReference save() {
        update account;
        return null;
    }
}


Sample2.png

Sample 3

Let's modify the previous example by making the account name and id controller member variables. We will make the account name member transient so that only record Id is being saved in the view state. The page and the controller code is shown below. When this page is posted back, we will need to retrieve the record again, apply the new values and then update the database. This highlights the main benefit of view state - making the job of a developer easier by automatically maintaining state between postbacks.
<apex:page controller="myController" >
     <apex:form >
        <apex:pageBlock title="My Content" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="My Content Section" columns="2">
                <apex:outputLabel for="aName">Account Name:</apex:outputLabel>
                <apex:inputText value="{!accountName}"/>              
            </apex:pageBlockSection>
        </apex:pageBlock>
      </apex:form>
</apex:page>

public with sharing class myController {

    private final Id accountId&nbsp;;
    transient public final String accountName {get; set; }
    
    public myController() {
        Account account = [select Id, Name from Account where id =&nbsp;:ApexPages.currentPage().getParameters().get('id')];
        accountId = account.Id&nbsp;;
        accountName = account.Name&nbsp;;
    }
    
    public PageReference save() {
        Account myAccount = [select name from Account where id =&nbsp;:accountId];
        myAccount.name = accountName&nbsp;;
        update myAccount;
        return null;
    }

}


Viewstate-sample3.png

Sample 4

Finally, let's add a new component to the page and observe the effect on view state. We will add a standard pageMessages component - the resulting view state now shows the controller state associated with this component.
<apex:page controller="myController1" >
     <apex:form >
        <apex:pageBlock title="My Content" mode="edit">
            <apex:pageMessages/>
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="My Content Section" columns="2">
                <apex:inputField value="{!account.name}"/>              
            </apex:pageBlockSection>
        </apex:pageBlock>
      </apex:form>
</apex:page>


Sample3.png

Best Practices for Optimizing View State

View state makes your job as a developer easier by automatically handling all the details for state management during postbacks. However, because the view state has to be transferred back and forth between the browser and Force.com, there could be a potential performance impact in terms of increased page load times when the view state becomes large. Visualforce also imposes a limit of 135K on your view state - if the view size exceeds this limit, an exception gets thrown.
Let us look at a few best practices to optimize view state.

Minimize Number of Forms on a Page

Update: With the introduction of Single View State in the Summer '12 release, a Visualforce page manages a single view state, even when the page contains multiple input forms. Though developers should still try and avoid using multiple form elements as recommended in the following section, it no longer has any bearing on the size of the View State for a Visualforce page.
Assume a page contains two forms - form 1 and form 2. Whichever form the user submits and causes a postback, the view state for the page needs to get transferred. To support this, each form on your page will have its own copy of view state. If the associated view state is large, instead of having multiple forms on a page, have a single form and use <apex:actionRegion> to submit portions of the form. This practice will ensure that only a single copy of the view state is associated with that page. In the example below, two forms are used to update Account fields and the related Contact attributes.

// Using two forms
<apex:page controller="MyController">

<apex:form>
   <apex:commandButton action="{!saveAccount}" value="Update Account"/>
    <!--Account attributes available for editing -->

</apex:form>

<apex:form>
    <apex:commandButton action="{!saveContacts}" value="Update Contacts"/>
     <!--Contact attributes available for editing -->
</apex:form>

</apex:page>


These two can be combined into a single form by leveraging the <apex:actionRegion> component.

// Combining into single form and leveraging <apex:actionRegion>
<apex:page controller="MyController">
  <apex:form>
     <apex:commandButton action="{!saveAccount}" value="Update Account"/>
     <!--Account attributes available for editing -->
   
     <apex:actionRegion>
       <apex:commandButton action="{!saveContacts}" value="Update Contacts"/>
     <!--Contact attributes available for editing -->
    </apex:actionRegion>

  </apex:form>
</apex:page>

You can find additional details on <apex:actionRegion> component here.

Declare Variables as Transient to Reduce View State

An instance variable declared as transient is not saved and is not transmitted as part of the view state. If a certain field is needed only for the duration of the page request and does not need to be part of the view state, declare it as transient. See an example below. Some Apex objects are automatically considered transient. For a full list of such objects and other details on transient, please refer to the docs.

<apex:page controller="ExampleController">
  The Current Time is&nbsp;: {!currentDateTime} <br/>
  <apex:form>
    <apex:commandLink value="refresh"/>
  </apex:form>
</apex:page>

public class ExampleController {

    transient DateTime currentDateTime;

    public String getCurrentDateTime() {
        if (currentDateTime == null) currentDateTime = System.now();
        return '' + currentDateTime;
    }
}

Recreate State versus Storing It in View State

View state should ideally contain only work in progress data (the current object being edited, multi-page wizard data, etc.) If you can reconstruct the data during postback, via a SOQL query or a web services call, do that instead of storing it in controller data members.

Use Custom Objects or Custom Settings to Store Large Quantities of Read-Only Data

Assume that your controller needs to call a Web service and parse a large response object. Storing it in view state may not even be an option given the size. Marking it as transient would incur the cost of an additional Web service call and parsing it again. In such instances, you could store the parsed response in a custom object and store just the record id to get to the parsed response. Custom settings provide another mechanism to cache data needed by your controller. Accessing custom settings is faster than access to custom objects since custom settings are part of your application's cache and does not require a database query to retrieve the data. Please consult the online documentation for additional details on Custom Setting.

Refine Your SOQL to Retrieve Only the Data Needed by the Page

Only retrieve (and store) the fields you need and also filter the data to only retrieve data needed by the page.

Refactor Your Pages to Make Its View Stateless

Instead of using apex:commandLink or apex:commandButton components (which need to be inside a apex:formcomponent) to invoke an action, use an apex:outputLink or other non-action method instead and implement the action through an apex:page action attribute - where it makes sense. The following code shows two ways to invoke a controller method called proccessData() - first with a commandLink, and then with an outputLink and auxiliary page.

// On this page we use a commandLink to invoke a method. CommandLink should be inside a 
// form and thus will have an associated view state
<apex:page controller="ExampleController" >
 <b>Example with command link </b>
 <br/><br/>
 <apex:form >   
     <apex:commandLink value="Process Data" action="{!processData}"/>
 </apex:form>
</apex:page>


//This page accomplishes the same without the need for a view state
<apex:page >
     <b> Example -  using outputLink </b>
     <br/> <br/>
     <apex:outputLink value="{!$Page.MyPage2}">Process Data</apex:outputLink>
</apex:page>

// On MyPage2 you can also invoke a method with an action attribute
<apex:page controller="ExampleController" action="{!processData}">
</apex:page>

Consider Doing Your Own State Management in Certain Cases

In certain cases, you may want to bypass the view state mechanism offered by Visualforce and do your own state management. In such cases, use a HTML FORM instead of apex:form. This technique is useful for dealing with Visualforce pages that may have to be served to mobile devices where the view state may be too large for the embedded browsers.

Summary

View state makes your job as a developer easier by automatically managing state during postbacks. The view state is very much under your control - and you can optimize the size of the view state by paying attention to transient variables, the number of forms on a page, using custom settings to store data and so on.

References

Lightning Inter-Component Communication Patterns

Lightning Inter-Component Communication Patterns If you’re comfortable with how a Lightning Component works and want to build producti...