Apex Triggers - 8 (Trigger Interview Question)
ฝัง
- เผยแพร่เมื่อ 4 ม.ค. 2023
- 💻 Join the Titan Community : Discover Exclusive Insights on LinkedIn / mycompany
💻 Explore the Power of Titan : Visit Our Official Website Now 🔗 titandxp.com/ - วิทยาศาสตร์และเทคโนโลยี
Hi Badal , In the past few weeks I have got immense confidence on Apex Triggers , Thank you for all your efforts.....
One thing I wanted to add is that we can have a check like only if Opportunity Amount field is updated then the whole logic should be applied else I guess there is no need to update the related accounts ?
Please correct me if I am wrong
Thank You
what if user updates the account on opportunity you also have to consider this scenario
Hi Why you use Map update the records instead of List, can we use list here to update the records?
On line 32 we are adding Account Ids based on change of amount field on opportunity but will it not trigger for every other field update?
Very helpful. Thank you so much sir.
Is we change parent of two opportunities, the total amount field on the account updates only one of the opportunity amounts. Why is it so ?
There was an issue in above trigger that I have updated the parent account of an opportunity in this scenario updated parents account total sum is updated properly but the old parent accounts total sum is showing incorrect.
Thank you brother.
thank you bro
Thank you so much bro ...
❤️
while inserting record getting this error OpportunityTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Class.OpportunityTriggerHandler.sumofoppamountmethod: line 39, column 1 Trigger.OpportunityTrigger: line 5, column 1
Hii Badal, you can use that same technique to count number of contact instead of using inner query.
Hi Yash, Thank you for sharing your feedback! While it's true that we can use the same technique, I always try to showcase different approaches so that others can explore different options.
Hello sir please try to delete all opportunities record for same account mean we created 2 opportunities for this account and deleted one then it working fine for delete operation but try to delete both opportunities in that case it still showing amount on account
Please can you write and show with apex handler
if(trigger.isUpdate)
{
for(Opportunity opp: trigger.new)
{
if((opp.AccountId != trigger.oldMap.get(opp.Id).AccountId) || (opp.Amount != trigger.oldMap.get(opp.Id).Amount))
{
accountsIds.add(opp.AccountId);
accountsIds.add(trigger.oldMap.get(opp.Id).AccountId);
}
}
}
This should be correct for Update scenario pls let me know if its right?
when i tried it hitting this error OpportunityTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object
Because u haven't put null check condition in your trigger
Hi! How do I filter it to capture only Closed Won Opportunities? Thank you.
Hello! You can modify the SOQL query in the code like this List aggrList = [
SELECT AccountId, SUM(Amount) totalAm
FROM Opportunity
WHERE AccountId IN :accIds AND StageName = 'Closed Won'
GROUP BY AccountId
];
@@sfdcninjas Thank you for your answer. I a, using this code for trigger, how do I add your shared code here:
trigger totalAmount on Opportunity (after insert, after update, after delete) {
Map acctIdOppoListMap = new Map();
Set acctIds = new Set();
List oppoList = new List();
if(trigger.isUpdate || trigger.isInsert){
for(Opportunity oppo : trigger.New){
if(oppo.AccountId != null){
acctIds.add(oppo.AccountId);
}
}
}
if(trigger.isDelete){
for(Opportunity oppo : trigger.old){
if(oppo.AccountId != null){
acctIds.add(oppo.AccountId);
}
}
}
if(acctIds.size() > 0){
oppoList = [SELECT Amount, AccountId FROM Opportunity WHERE AccountId IN : acctIds];
for(Opportunity oppo : oppoList){
if(!acctIdOppoListMap.containsKey(oppo.AccountId)){
acctIdOppoListMap.put(oppo.AccountId, new List());
}
acctIdOppoListMap.get(oppo.AccountId).add(oppo);
}
List acctList = new List();
acctList = [SELECT Amount__c FROM Account WHERE Id IN: acctIds];
for(Account acct : acctList){
List tempOppoList = new List();
tempOppoList = acctIdOppoListMap.get(acct.Id);
Double OpportunityAmount = 0;
for(Opportunity oppo : tempOppoList){
if(oppo.Amount != null){
OpportunityAmount += oppo.Amount;
}
}
acct.Amount__c = OpportunityAmount;
}
update acctList;
}
}
Thank you.
Hi , I am really sorry for late reply you can modify this line like this oppoList = [SELECT Amount, AccountId FROM Opportunity WHERE AccountId IN : acctIds AND StageName = 'Closed Won'];
why you are not using handler class. is there any specific reason
I agree with you, why are you didn't use handler class :( But thank you
@EmadKhan77
method when you use handlerclass:
public static void updateOpportunityAmountinAccount(MapoldOppMap,List newOpps ){
system.debug('Called here');
set accountIdList = new Set();
Map accMapToUpdate = new Map();
//Map oppMap= new Map();
if(Trigger.IsInsert){ // for insert scenario
system.debug('Called here1');
for(Opportunity opp : newOpps){
if(opp.AccountId!=null){
accountIdList.add(opp.AccountId);
//oppMap.put(opp.AccountId,opp);
}
}
}
else if(Trigger.IsUpdate){ // for update scenario
system.debug('Called here2');
for(Opportunity opp : newOpps){
if(opp.AccountId!=oldOppMap.get(opp.Id).AccountId){ // will be executed when we chnage the parent of an opp record
system.debug('Called here2a');
accountIdList.add(opp.AccountId);
accountIdList.add(oldOppMap.get(opp.Id).AccountId);
//oppMap.put(opp.AccountId,opp);
}else { // will be executed when Amount of the opp record will be changed
system.debug('Called here2b');
accountIdList.add(opp.AccountId);
}
}
}
else if(Trigger.isDelete){
system.debug('Called here3');
for(Opportunity opp: oldOppMap.values()){
accountIdList.add(opp.AccountId);
}
}
if(!accountIdList.IsEmpty()){ // using aggregate funtions
List aggResult = [select AccountId ids,sum(Amount) totalAmount
from Opportunity where AccountId IN : accountIdList group by AccountId];
for(AggregateResult aggr: aggResult){
system.debug('Entered 1');
Account acc = new Account();
acc.Id= (Id)aggr.get('ids');
acc.Opportuniy_Total_Amount__c = (Decimal)aggr.get('totalAmount');
accMapToUpdate.put(acc.Id,acc);
system.debug('total Amount is-->'+acc.Opportuniy_Total_Amount__c);
}
}
if(!accMapToUpdate.isEmpty()){
update accMapToUpdate.values();
}
}
undelete is not working please give the code link in the description
I apologize for any inconvenience, but I do not currently have any links available for the code. However, I kindly suggest reviewing the video again as I have demonstrated the undelete operation and the code is functioning properly.
Thank you
Brother if we remove line 58, then I guess line 68 to 77 will not be required?, please let me know
Hi bro, Based on a quick analysis line 58 seems to be responsible for updating the Total_Opp_Amount__c field on the related Account records. If line 58 is removed, it's possible that the Total_Opp_Amount__c field won't be updated correctly.
Ok bro, if suppose the amount field is blank in all the related opportunities of a account, then the aggregate function will give totalAm as 0 for that account? Please me know
Hi
I have scenario where total amount is not updating in the account field change on opportunity.
If account has only 1 opportunity and if parent account gets change, then total amount is not updating to 0.
Note: if i delete that opportunity, then total amount is updating to 0.
Sorry for late reply buddy, can you please show me your code
Even I got stuck in here! This is actually an edge case where if we re-parent the last opportunity on account, then in that scenario the code that you've provided is failing ...
Pls let us know how to cover that scenario as well..all I'm thinking is to write another query to fetch accs with value in the Total_Opp_Amount__C field and size of opportunities on the acc is Zero.
@@sfdcninjas
public class OpportunityTriggerHandler {
public static void totalAmountOfOpportunities(List newOppList , Map oldOppList){
Set accId = new Set();
if(! newOppList.isEmpty()){
for(Opportunity opp : newOppList){
accId.add(opp.AccountId);
}
for(Opportunity opp : newOppList){
if(oldOppList != NULL && opp.AccountId != oldOppList.get(opp.Id).AccountId){
accId.add(opp.AccountId);
accId.add(oldOppList.get(opp.Id).AccountId);
}
}
}
List accList = new List();
if(! accId.isEmpty()){
List aggrResult = [SELECT AccountId Ids, SUM(AMOUNT) totalAmt
FROM OPPORTUNITY
WHERE AccountId IN : accId
GROUP BY AccountId];
if(! aggrResult.isEmpty()){
for(AggregateResult aggr : aggrResult){
Account acc = new Account();
acc.Id = (Id)aggr.get('Ids');
acc.Total_Amount_Of_Opportunities__c = (Decimal)aggr.get('totalAmt');
accList.add(acc);
}
}
else{
for(Id accIds : accId){
Account acc = new Account();
acc.Id = accIds;
acc.Total_Amount_Of_Opportunities__c = 0;
accList.add(acc);
}
}
update accList;
}
}
Same thing is happening w me did you find out the issue?
@@sfdcninjas PFB the code where the scenario mentioned in the comment is not working
trigger TriggerN8Opp on Opportunity (after insert, after update, after delete, after undelete) {
Set accIds = new Set();
if (trigger.isAfter && (Trigger.isInsert || Trigger.isUndelete)){
if (!Trigger.new.isEmpty()){
for (Opportunity opp : Trigger.new){
if (opp.AccountId != null){
accIds.add(opp.AccountId);
}
}
}
}
if (trigger.isAfter && trigger.isUpdate){
if (!Trigger.new.isEmpty()){
for (Opportunity opp : Trigger.new){
if (Trigger.oldMap.get(opp.Id).AccountId != opp.AccountId){
accIds.add(Trigger.oldMap.get(opp.Id).AccountId);
accIds.add(opp.AccountId);
}
else{
accIds.add(opp.AccountId);
}
}
}
}
if (trigger.isAfter && trigger.isDelete){
if (!Trigger.old.isEmpty()){
for (Opportunity opp : Trigger.old){
if (opp.AccountId != null) {
accIds.add(opp.AccountId);
}
}
}
}
if (!accIds.isEmpty()){
List aggrList=[select AccountId ids, sum(Amount) sumAmt from Opportunity
where AccountId IN :accIds group by AccountId];
Map accMap = new Map ();
if (!aggrList.isEmpty()){
for (AggregateResult aggr : aggrList){
Account acc = new Account();
acc.Id = (Id) aggr.get('ids');
acc.Total_Opp_Amount__c=(Decimal) aggr.get('sumAmt');
accMap.put(acc.Id, acc);
}
}
else {
for (Id accId : accIds){
Account acc = new Account();
acc.Id = accId;
acc.Total_Opp_Amount__c=0;
accMap.put(acc.Id, acc);
}
}
if (!accMap.isEmpty()){
update accMap.values();
}
}
}
Bro you not doing as per best practice where is the trigger helper method
Hi Buddy, In my further videos I have implemented handler class please check them out.
Hi, Can anyone explain why are we creating account Records here?
We are not creating Account records ,it is one of the way to update records.Correct me if I am wrong
Hii why we used totalAm field it doe not exist in opportunity obj
Hi there, basically in an aggregated query if we are using an aggregate function like we are “sum(amount) totalam” here sum is the aggregated function, amount is the field on opportunity object and totalam is the variable by which we can access the aggregated result
thank you bro for this awesome work and i have a scenario .if if are handling bulk delete an account does not have any opp but others have in this scenario else of Aggregate function will not execute .i have tried for this scenario plz have a look and guide me further
trigger OppAmountSumOnAccount on Opportunity(after insert,after undelete,after delete,after update){
set accountIds = new set();
if(!trigger.new.isEmpty()){
if(trigger.isAfter && (trigger.isInsert || trigger.IsUndelete)){
for(opportunity opp : trigger.new){
if(opp.accountid != null){
accountIds.add(opp.accountId);
}
}
}
if(trigger.isAfter && trigger.isUpdate){
for(opportunity opp : trigger.new){
if(opp.accountid != null){
accountIds.add(opp.accountId);
}
if(trigger.oldMap.get(opp.id).accountId != null && (opp.accountId != trigger.oldMap.get(opp.id).accountId || opp.amount != trigger.oldMap.get(opp.id).amount)){
accountIds.add(trigger.oldMap.get(opp.id).accountId);
}
}
}
}
if(!trigger.old.isEmpty()){
if(trigger.isAfter && trigger.isDelete){
for(opportunity opp : trigger.old){
if(opp.accountid != null){
accountIds.add(opp.accountId);
}
}
}
}
map accMap = new map();
if(!accountIds.isEmpty()){
list agrList = [select accountId ids,sum(amount) sumAmnt from opportunity
where accountId IN : accountIds group by AccountId];
if(!agrList.isEmpty()){
for(AggregateResult agr: agrList){
account acc = new account();
acc.id = (id)agr.get('ids');
acc.totalOppAmount__c = (Decimal)agr.get('sumAmnt');
accMap.put(acc.id,acc);
if(accountids.contains(acc.id)){
accountids.remove(acc.id);
}
}
}
//here we are handling account which doesnot have any associated opportunity after the action
for(id accid:accountids){
account acc1 = new Account();
acc1.id =accid;
acc1.totalOppAmount__c = 0;
accMap.put(acc1.id,acc1);
}
}
if(!accMap.isEmpty()){
update accMap.values();
}
}