Preface – This post is part of the Write Your First Intermediate Trigger series.
This chapter is going to change your life.
Once you understand how to use SOQL in triggers, the whole world of Salesforce opens up to you. Sure, you can still do a lot with a simple trigger, but once you start combining SOQL, it’s hard to find something you can’t do with it!
Now why is it so important to mix SOQL with Apex? Traditionally in a trigger, you only really have access to the record that’s being created or edited. You can do anything you want, but only on that record! Once you throw SOQL into the mix, every record in Salesforce becomes available to you at any time. Anything! Even abstract records, like deleted records, approval processes, sharing rules, etc. Anything you can conceive and more is available to you – you’ll truly be amazed at what Salesforce has opened up to you with code!
What we’ll do this chapter is build a trigger that dedupes leads with contacts. So if anyone tries to create a new lead that has the same email as an existing contact, we’ll give the user an error.
Why is this trigger the perfect template for all your triggers moving forward?
This chapter is the most important chapter in all of Sfdc99! So pay close attention and stay focused, because things are gonna get real fun!
Next post: Using Apex variables inside a SOQL query!
trigger nelead on Lead (before insert,before update) {
//system.debug(‘the value is’ +add);
//list emailids=[select email from Contact where email !=null];
for(Lead Le:trigger.new){
list ContactList = [SELECT Id, Email FROM Contact];
if(Le.email==null){
le.addError(’email address should not be empty’);
}else if(le.email ==ContactList.Email )
{
le.addError(‘There is already contact exisit with the email Address. Please enter another email address’);
}
}
}
getting error “Error Error: Compile Error: Variable does not exist: Email at line 12 column 32
help me on that
can’t we use . notation to compare the new lead email address with existing contact list.
got a requirement like to calculate average in account based on particular record type of case. My requirement is:
I have a field called ARP in account currency. I want to calculate overall average of ARP field in particular record type called customer order whether Case details either new or add-on.
So I’m trying write a trigger a trigger.
Everything is working but after delete event is not working means.
Example when i create a case with ARPU will be 21.And if i delete the case it’s still showing 21 in account level.Even i am trigger.old in trigger to handler class.
My trigger code
trigger ForARPU on case (after insert,after update,after delete)
{
if(Trigger.isAfter && trigger.isDelete)
{
//It will call a static method called ARPUInsert in ARPUCases class.
ARPUCases.ARPUDelete(Trigger.Old);
}
}
My handler class
public static void ARPUDelete(List CaseTriggers)
{
/**
* This method is to caluclate average of all ARPU amounts with case have customer order recordtype
* as well as case details with either ADD-On (OR) New Subscription and update in related account
* field called ARPU.
* This method will fire only when any case with record type called customer order is deleted.
*/
if (Trigger.IsDelete)
{
for (Case s : CaseTriggers)
{
if(s.RecordTypeId == recordTypeId && s.Case_Details__c ==’New Subscription’ || s.Case_Details__c ==’Add On’ )
{
// Loop through and add caseId’s to the list.
CaseIDs.add(s);
}
}
system.debug(‘Case:IDS ‘ + caseIds);
/** @Var CaseAccountIds – to get accountId’s of cases with list called CaseIDs */
set CaseAccountIds = new set();
List Accountstoupdate =new List();
for(Case c : [SELECT Id,ARPU__c,accountId FROM Case WHERE Id IN :CaseIDs])
{
// Loop through and add AccountId’s to the list.
CaseAccountIds.add(c.AccountId);
}
system.debug(‘CaseAccount IDS ‘ + CaseAccountIds);
/** @Var Accountswithcases-to get account details to caluclate average */
/** @Var results-to get average of particular account based on the cases */
List Accountswithcases = [select Id,name,ARPU__c from Account where id =:CaseAccountIds];
system.debug(‘Accounts With Cases ‘ + accountsWithCases);
Map results = new Map(
[SELECT AccountId Id, AVG(ARPU__c) average FROM Case WHERE AccountId = :Accountswithcases GROUP BY AccountId]);
system.debug(‘Results ‘ + results);
For(account a1: Accountswithcases)
{
if(results.get(a1.Id) != null)
{
// Loop through aggregate results array and typecast the average of ARPU and update in account level.
system.debug(‘Updating Account ARPU ‘ + a1.ARPU__c);
a1.ARPU__c = (Decimal)results.get(a1.Id).get(‘average’);
system.debug(‘Updated Account ARPU ‘ + a1.ARPU__c);
Accountstoupdate.add(a1);
}
//accSet.addAll(Accountstoupdate);
//Accountstoupdate.addAll(accSet);
}
if(Accountstoupdate.size()>0)
{
// DML statement to update all the accounts related with cases.
system.debug(‘Updating Records ‘ + AccountsToUpdate);
update Accountstoupdate;
}
}
}
}
I don’t where iam doing wrong.
My debug Logs[![Debug Logd][1]][1]
05:27:39.0 (73030463)|USER_DEBUG|[88]|DEBUG|Case:IDS (Case:
{Id=500N0000004OLupIAG, IsDeleted=false, CaseNumber=00039379,
ContactId=null,AccountId=001N000000qsgRbIAI,
RecordTypeId=01290000000sF3LAAU, Status=New,ARPU__c=19.51
05:27:39.0 (90125313)|USER_DEBUG|[97]|DEBUG|CaseAccount IDS {}
05:27:39.0 (91805508)|USER_DEBUG|[101]|DEBUG|Accounts With Cases ()
05:27:39.0 (91869894)|USER_DEBUG|[102]|DEBUG|Accounts With Cases Size0
05:27:39.0 (96284070)|USER_DEBUG|[105]|DEBUG|Results {}
05:27:39.0 (96410554)|VARIABLE_ASSIGNMENT|[106]|a1|null|
Hi David!
Before looking at your solution for the trigger to deduplicate leads and contacts, i’ve decided to try to code it by myself. Here’s the trigger i’ve just code:
trigger LeadContactDuplicate on Lead (before insert, before update) {
for(Lead newLead : Trigger.new){
Boolean thereIsMatch = false;
List ContactList = [SELECT Id, Email FROM Contact];
for(Contact currentContact : ContactList){
if(!thereIsMatch){
if(currentContact.Email == newLead.Email){
thereIsMatch = true;
}else{
thereIsMatch = false;
}
}
}
if(string.isBlank(newLead.Email)){
newLead.addError(‘You must specify an email for the Lead.’);
}else if(thereIsMatch){
newLead.addError(‘The specified email for the Lead matches with an existing contact.’);
}
}
}
Do you think it will work? I hope so ;)
Thanks
I hope so! Try testing it out in your org!
Where is thereIsMatch variabledeclared??
Hi David ,
I have a case in Trigger please provide solution for that.I have written code for insert event but i am not able code for update and delete.
Requirement is given below.
Requirement
XYZ Containers is a MNC with offices in multiple locations, each location is represented with a Branch custom object.
Data model
Following is structure of Branch Object.
Field Name Field Type Relevance
1 Name text Name of Branch
2 Parent Branch self lookup Parent Branch of this branch, for ex.
Current branch is “Gurgaon”, parent Branch
could be “Haryana”. Parent branch of
Haryana could be India, and India’s parent
branch could be “Asia”
3 Top Parent Branch self lookup Points to Top branch in hierarchy i.e. for “Gurgaon”
it should be “Asia
4. Branch Id Chain Long Text Pipe ( | ) separated IDs of all branches above
current branch, including ID of current branch in last. For ex.
Gurgaon Branch ID : 100
Haryana Branch ID : 101
India Branch ID : 102
Asia Branch ID : 103
The ID Chain for Gurgaon should be “103 | 102 | 101 | 100”
trigger FillBranch on Branch__c (after insert,after update,after delete,after undelete) {
if(trigger.isInsert || trigger.isUndelete){
System.debug(‘Undelete is :: ‘+ trigger.new);
List branchRecList = [select id,name,top_parent_Branch__c,parent_Branch__c,Branch_Id_Chain__c from branch__c where id in : trigger.newMap.keySet()];
Map<String,List> branchMap = new Map<String,List>();
for(Branch__c branch : branchRecList){
branch.Branch_Id_Chain__c = branch.name;
branch.top_parent_Branch__C = null;
}
if(branchRecList.size()>0)
update branchRecList;
}else if(trigger.isDelete){
String query = ‘select id,name,top_parent_Branch__c,parent_Branch__c,Branch_Id_Chain__c from branch__c where Branch_Id_Chain__c like ‘;
for(Branch__C branch : trigger.old){
query += ‘ \’%’ + branch.name + ‘%\’ OR ‘;
}
updateOldValues(query);
}else if(trigger.isUpdate){
Map<String,List> branchMap = new Map<String,List>();
Set IdSet = new Set();
Boolean flag=false;
List branchRecList = [select id,top_parent_Branch__r.name,name,top_parent_Branch__c,parent_Branch__c,Branch_Id_Chain__c from branch__c where id in : trigger.newMap.keySet()];
String query = ‘select id,name,top_parent_Branch__c,parent_Branch__c,Branch_Id_Chain__c from branch__c where Branch_Id_Chain__c like ‘;
for(Branch__c branch : branchRecList){
if(trigger.oldMap.get(branch.id).parent_Branch__C != branch.parent_Branch__C){
branch.Branch_Id_Chain__c = branch.name;
branch.top_Parent_Branch__C = null;
flag=true;
query += ‘ \’%’ + branch.name + ‘%\’ OR ‘;
}
if(branch.parent_Branch__c != null){
if(branch.top_parent_branch__C==null){
branch.top_parent_Branch__C = branch.parent_Branch__c;
}
List tempList = new List();
if(branchMap.containsKey(branch.top_parent_Branch__C))
tempList = branchMap.get(branch.top_parent_Branch__C);
tempList.add(branch);
branchMap.put(branch.top_parent_Branch__C,tempList);
}else{
branch.top_parent_Branch__c = null;
}
}
List branchLst = new List();
for(Branch__c bran : [select id,name,top_parent_Branch__c,parent_Branch__c,Branch_Id_Chain__c from branch__c where id in : branchMap.keySet()]) {
if(branchMap.get(bran.id) !=null){
for(branch__C branchInner : branchMap.get(bran.id)){
if(bran.parent_Branch__C!=null)
branchInner.top_parent_Branch__c = bran.parent_Branch__C;
if(!branchInner.Branch_Id_Chain__c.contains(bran.name)){
branchInner.Branch_Id_Chain__c += ‘ | ‘ + bran.name;
branchLst.add(branchInner);
}
}
}
}
if(branchLst.size()>0){
update branchLst;
}
if(flag==true)
updateOldValues(query);
}
void updateOldValues(String query){
List branchList = Database.query(query.subString(0,query.lastIndexOf(‘OR’)));
if(branchList!=null && branchList.size()>0){
for(Branch__C brnc : branchList){
brnc.top_parent_Branch__c = null;
brnc.Branch_Id_Chain__c = brnc.name;
}
update branchList;
}
}
}
Even I need help for this can you provide the whole trigger
sorry if I am asking very basic questions
can u explain what are’ abstract records ‘
thanks in advance
Thankyou so much David! I was really slogging hard to learn coding in SFDC but after i found your website it made my life easier, i actually found it so interesting that i spend 3-4 hours daily to learn as much as i can. David YOU ROCK!
Very happy I could help you Abhishek!!
Hi David!
Really enjoying your sfdc99 site! Very helpful for someone who can read code, but can NOT write it! I have been “adopting” pieces of code from some triggers we have had built and applying those to put together my own triggers. There’s one thing I am having trouble understanding though. When the code calls out a custom object, for example “Nomination”, how do you know what abbreviation to use? (See first code snippit below)
Any wisdom you can share on this is greatly appreciated!!!
//ids of all nominations that are related to a candidacy
Set NominationIDs = new Set();
//candidacy set
setcandidacySet = new set();
if(trigger.isDelete)
{
for(nomination__c nom : trigger.old) <—————–REFERRING TO "nom"
{
if(nom.candidacy__c != null)
{
candidacySet.add(nom.candidacy__c);
}
}
}
else
{
for(nomination__c nom : trigger.new)
{
if(!trigger.isUndelete)
{
nomination__c nomOld = Trigger.oldMap.get(nom.Id);
Glad you’re enjoying!
Two posts you need to check out:
1. Variables
https://www.sfdc99.com/2013/09/28/data-types-strings-dates-numbers-and-sobjects/
2. Loops
https://www.sfdc99.com/2013/10/06/loops-for-and-foreach-loops/
Long story short, you can name your variables anything you want!
David
hi david , fr awesome wonders !!
if contact 1 addres_for_contact is: ab
contact 1 addres_for_contact is: cd
then, in account object:
final_address_of_contacts__c is: ab,cd
using maps i have to do the trigger , but this is not fine .any idea where i m wrong
trigger populateAllContactsAddress_onAccount on Contact (after insert,after update)
{
set conAccId =new set();
for(contact con: trigger.new)
{
if(con.AccountId!=null)
conAccId.add(con.AccountId);
}
List lst= [select AccountId, Address_for_contact__c from contact where AccountId In: conAccId];
Map<id,list> mapAcc = new map <id ,List>();
for (Contact con: lst)
{
if(mapAcc.get(con.Accountid)==null)
{
mapAcc.put(con.AccountId,new List());
}
mapAcc.get(con.AccountId).add(con);
}
list acConAddress = new list();
for(contact con :trigger.new)
{
if(mapAcc!=null)
list aci = mapAcc.get(con.AccountId);
Account ac = new Account(id=con.AccountId);
string Local =”;
Local = local+ ‘,’ + con.AccountId;
ac.Final_address_of_contacts__c = Local;
acConAddress.add(ac);
}
update acConAddress;
}
Needs more System.debug!
https://www.sfdc99.com/2014/02/22/debug-your-code-with-system-debug/
sorry
i have a doubt abt junction objects
SELECT Id, ProductCode, UnitPrice from Pricebook2
when i run this on workbench its nt executing cz pricebook2 has no such fields.(product code, unit price ) as both these fields are in pricebookentry.
junction objects …how to do it
related to first comment##
Query PriceBookEntry instead =)
You can access PriceBook2 values using dot notation!
David,
I love the format of your site. Excellent work thus far – thank you! I have a question: Is it possible to query junction objects such as the PricebookEntry object to list the product code, unit price, and description of a product? Thank you!
It certainly is possible! In fact, you’ll be amazed at how many things you can query with SOQL – everything you expect is there and then some!
Here’s an example with PricebookEntry:
[SELECT Id, ProductCode, UnitPrice from Pricebook2]
You can do the same for line items, for example, on an Opportunity using the OpportunityLineItem object.
More info here:
https://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_pricebookentry.htm
If you try using Workbench, you’ll see the full list of objects you can query with SOQL!
https://www.sfdc99.com/2013/06/08/where-to-write-soql-queries/
Hope this helps!
David
Hi David,
Thank you for your reply. I was thrown off because when stepping downwards in my query, I forgot to use the plural form.
David, All the contents present is wonderful and great. I hope to see the remaining contents soon. One thing I must say When i started learning SFDC, I never came across such information. Its really good for people who are starting/beginner to learn. Appreciate your passion to help the beginner’s.
Thank you Sunil, I enjoy making this site a lot!!!
David,
I just discovered your site this evening and have read all the content and can’t wait to read all that is yet to come!!!! I have been Salesforce tier 2 support then onto a Senior Business Analyst and now becoming a Junior Developer and your posts are certainly a big help to me! I am glad to find someone as excited about code as me! I was late to fall into it but I fell hard and can’t get enough information now! Great work sir!
Josh,
Glad you like the site! I wouldn’t have rebuilt it if it wasn’t for comments like these, so thank you too from me!
If being a Salesforce developer is your dream then I promise that you can do it! And if for any reason you get stuck or need help, I am here to help =)
David
P.S. How’d you find the site?