function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Kerri Mesa 18Kerri Mesa 18 

Apex to Update a record when related Opportunity is updated

I am trying to build out a trigger and trigger handler to update a record related to an Opportunity when the Opportunity is updated. We need to do this without editing the related record (Legal Agreement)

Here is the trigger handler class I am working with:
public class OpportunityTriggerHandler {
    public static void OpportunityTriggerHandler(){       
    	Map <Id,  Opportunity> mapOpportunity = new Map <Id, Opportunity>();
    	List<Legal_Agreements__c> listLA = new List<Legal_Agreements__c>();
    	List<Legal_Agreements__c> LAUpdate = new list <Legal_Agreements__c>();
   
    		listLA = [SELECT Id, Status__c, test__c, Opportunity_Stage__c FROM Legal_Agreements__c WHERE Opportunity__r.Id IN : mapOpportunity.keySet() ];
  			system.debug('Legal Agreement list size ' + listLA.size());
        
    		if(listLA.size() > 0) {
       			 for (Legal_Agreements__c LA : listLA ) {
           			 LA.test__c = LA.Opportunity__r.StageName;
                     LA.test__c = LA.Opportunity_Stage__c;
        		}
    		}
	}
}
And this is the trigger:
trigger OpportunityTrigger on Opportunity (before insert, before update, before delete, after insert, after update, after delete) {
      OpportunityTriggerHandler handler = new OpportunityTriggerHandler();

This is all really rough at this point, but if anyone could guide me, I'd appreciate it.
 
Best Answer chosen by Kerri Mesa 18
Andrew GAndrew G
Hi Kerri.
Apologies as my code seems to have confused you.
First, the error you have is because you are trying to return the method name as a List. 
public class OpportunityTriggerHandler {
    public static void OpportunityTriggerHandler(){       
        if(Trigger.isInsert && Trigger.isAfter) {
            List<Legal_Agreeements> toUpdate = new List<Legal_Agreements>();
            toUpdate = updateAgreeements(Trigger.NewMap);
            if(toUpdate.size()>0){
                try {
                    update toUpdate
                } catch(DmlException e) {
                    System.debug('The following exception has occurred: ' + e.getMessage());
                }
            }
        }
        if(Trigger.isUpdate && Trigger.isAfter) {
            //other code as required for after udpate
        }
    }

//update Legal Agreements
    public List<Legal_Agreements> updateAgreements(Map<Id,Opportunity> mapOpps){       
        List<Legal_Agreements__c> listLA = new List<Legal_Agreements__c>();
        List<Id> openOppIds = new List<Id>();
    for(Opportunity o : mapOpps){ 
      if(o.StageName.Contains('Closed - ')){ 
        openOppIds.add(o.Id);
       }
     } 

    listLA = [SELECT Id, Status__c, test__c, Opportunity_Stage__c FROM Legal_Agreements__c WHERE Opportunity__r.Id IN : openOppIds];
    system.debug('Legal Agreement list size ' + listLA.size());
        
            if(listLA.size() > 0) {
                    for (Legal_Agreements__c LA : listLA ) {
                        LA.test__c = LA.Opportunity__r.StageName;
                                 LA.test__c = LA.Opportunity_Stage__c;
                }
                return listLA;
            }
    }
}//other methods..
}

I think this would go closer to what you are chasing.  (again uncompiled code)



Regards
Andrew

All Answers

Andrew GAndrew G
Hi Kerri

Everyone will have a different take on how to do Triggers and Handlers.  This post gives an example of my structures.
https://developer.salesforce.com/forums/ForumsMain?id=9062I000000IKZFQA4
The post and code is a little long but gives a bit of an explanation, not just code.  And the selected answer has the meat of the reply.

The other way to do it, is along the lines of how you are invoking it.  By the single line calling the Handler and then kicking straight to the code.
My only thoughts on that would be to ensure you segment the code to be invoked as required.  Your current structure would see the entire Handler being invoked multiple times on the one DML event.  That is, the trigger is set to fire on before and after and insert and update and delete.
So every DML (e.g. insert ) will see the code run twice.  And since it also runs twice on delete, you may run into so problems there.

I would look to breaking the Handler into methods e.g.
//update Legal Agreements
    public List<Legal_Agreements> updateAgreements(Map<Id,Opportunity> mapOpps){       
    	List<Legal_Agreements__c> listLA = new List<Legal_Agreements__c>();
   
	listLA = [SELECT Id, Status__c, test__c, Opportunity_Stage__c FROM Legal_Agreements__c WHERE Opportunity__r.Id IN : mapOpps.keySet() ];
	system.debug('Legal Agreement list size ' + listLA.size());
        
    		if(listLA.size() > 0) {
       			 for (Legal_Agreements__c LA : listLA ) {
           			 LA.test__c = LA.Opportunity__r.StageName;
                                 LA.test__c = LA.Opportunity_Stage__c;
        		}
                return listLA;
    		}
	}
}
I would then look at how I want those records updated within the context of the Handler, and therefore the trigger events.
public class OpportunityTriggerHandler {
    public static void OpportunityTriggerHandler(){       
        if(Trigger.isInsert && Trigger.isAfter) {
            List<Legal_Agreeements> toUpdate = new List<Legal_Agreements>();
            toUpdate = updateAgreeements(Trigger.NewMap);
            if(toUpdate.size()>0){
                try {
                    update toUpdate
                } catch(DmlException e) {
                    System.debug('The following exception has occurred: ' + e.getMessage());
                }
            }
        }
        if(Trigger.isUpdate && Trigger.isAfter) {
            //other code as required for after udpate
        }
    }

    public List<Legal_Agreements> updateAgreements(Map<Id,Opportunity> mapOpps){
        //the required code
    }
//other methods..
}

As I said, there are many ways to build handlers, but some core things to consider are
1.  Code reuse by using Methods for the heavy lifting and not replicating code.
2.  Consider when we want the code to fire and test for the Trigger events as required. Be that in the Trigger code or the Handler code depending on prefered structure.


HTH
Andrew

note: all code samples are not compiled so are not guarantee'd to be syntacticly correct.
Kerri Mesa 18Kerri Mesa 18
Thank you very much, Andrew. I have a ways to go, but have been formatting my code as follows. I'm getting an error with the "updateAgreements" list in particular (likely with much more at this point). 
 
public class OpportunityTriggerHandler{
 public List<Legal_Agreements__c> updateAgreements(Map<Id,Opportunity> mapOpps){  
    List<Legal_Agreements__c> listLA = new List<Legal_Agreements__c>();
  
        for(Opportunity o : mapOpps){
            if(o.StageName.Contains('Closed - ')){
               return updateAgreements; 
            }
        }    
       

	listLA = [SELECT Id, Status__c, test__c, Opportunity_Stage__c 
              FROM Legal_Agreements__c 
              WHERE Opportunity__r.Id IN : mapOpps.keySet()];
	system.debug('Legal Agreement list size ' + listLA.size());

    		if(listLA.size() > 0) {
       			 for (Legal_Agreements__c LA : listLA ) {
           			 LA.test__c = LA.Opportunity__r.StageName;
                     LA.test__c = LA.Opportunity_Stage__c;
        		}
                return listLA;
    		}
 
    public void OpportunityTriggerHandler2{     
        if(Trigger.isInsert && Trigger.isAfter){
            
            List<Legal_Agreements__c> toUpdate = new List<Legal_Agreements__c>();
            	toUpdate = updateAgreements(Trigger.NewMap);
            
            if(toUpdate.size()>0){
                try {
                    update toUpdate;
                } catch(DmlException e) {
                    System.debug('The following exception has occurred: ' + e.getMessage());
                }
            }
        }
      /*f(Trigger.isUpdate && Trigger.isAfter) {

        }*/
    } 
}

 
Andrew GAndrew G
Hi Kerri.
Apologies as my code seems to have confused you.
First, the error you have is because you are trying to return the method name as a List. 
public class OpportunityTriggerHandler {
    public static void OpportunityTriggerHandler(){       
        if(Trigger.isInsert && Trigger.isAfter) {
            List<Legal_Agreeements> toUpdate = new List<Legal_Agreements>();
            toUpdate = updateAgreeements(Trigger.NewMap);
            if(toUpdate.size()>0){
                try {
                    update toUpdate
                } catch(DmlException e) {
                    System.debug('The following exception has occurred: ' + e.getMessage());
                }
            }
        }
        if(Trigger.isUpdate && Trigger.isAfter) {
            //other code as required for after udpate
        }
    }

//update Legal Agreements
    public List<Legal_Agreements> updateAgreements(Map<Id,Opportunity> mapOpps){       
        List<Legal_Agreements__c> listLA = new List<Legal_Agreements__c>();
        List<Id> openOppIds = new List<Id>();
    for(Opportunity o : mapOpps){ 
      if(o.StageName.Contains('Closed - ')){ 
        openOppIds.add(o.Id);
       }
     } 

    listLA = [SELECT Id, Status__c, test__c, Opportunity_Stage__c FROM Legal_Agreements__c WHERE Opportunity__r.Id IN : openOppIds];
    system.debug('Legal Agreement list size ' + listLA.size());
        
            if(listLA.size() > 0) {
                    for (Legal_Agreements__c LA : listLA ) {
                        LA.test__c = LA.Opportunity__r.StageName;
                                 LA.test__c = LA.Opportunity_Stage__c;
                }
                return listLA;
            }
    }
}//other methods..
}

I think this would go closer to what you are chasing.  (again uncompiled code)



Regards
Andrew
This was selected as the best answer
Kerri Mesa 18Kerri Mesa 18
Ah got it. Thank you very much for your help! :)