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
Steve KucklincaSteve Kucklinca 

Help with fixing trigger to create a junction object record - keep getting errors Please Help!

I have the following code for a trigger in which I am trying to create aa junction object record when a field on one of the parent objects is updated Master Detail relation from Opportunity and Merchant_Application__c to junction object MerchOpps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
trigger MerchOppsRecord on Merchant_Application__c ( after insert, after update){

             for (Merchant_Application__c ma : Trigger.new) {
            if(ma.Completed__c != 'Completed '){
            MerchOpps__c mo = new MerchOpps__c(
            
        
            ChildofMA__c = ma.Id
           
            
            );
            
            insert mo;
            
            }
            
            }
            }


What is beyong my level of skill, and thank you to the variety who have helped get me this far, is that this only incorporates 1 Master object as I get the error:

Apex script unhandled trigger exception by user/organization: 005A00000042sXs/00DK000000W47xw Source organization: 00DA0000000gi0U (null)

MerchOppsRecord: execution of AfterUpdate

 

caused by: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Opportunity]: [Opportunity]

 

Trigger.MerchOppsRecord: line 13, column 1


How do I incorporate both Master Objects?

Even were I to edit to this code

trigger MerchOppsList on Merchant_Application__c (after insert, after update){ 
List<MerchOpps__c> MO = new List<MerchOpps__c>();

             for (Merchant_Application__c ma : Trigger.new) {
                MerchOpps__c M = new
MerchOpps__c         (   Account__c = ma.Account_Name__r.id , ChildofOpp__c = 'ASSIGN_OPPORTUNITY_ID', ChildofMA__c = ma.Id);
             
MO.add(M); 

insert MO;}

I would get error indicating Assign_Opportunity_ID is invalid

where would I find this value to correct this?
Best Answer chosen by Steve Kucklinca
logontokartiklogontokartik
Sorry. I forgot to put .Id

trigger MerchOppsRecord on Merchant_Application__c ( after insert, after update){

	Set<Id> accountIds = new Set<Id>();
	Map<Id,Opportunity> accountOpportunityMap = new Map<Id,Opportunity>();
	// Get the parent Account Ids from all the Merchant Application records,
	for(Merchant_Application__c ma : Trigger.new){
		accountIds.add(ma.Account__c); // Assuming Account__c is the fields that maps to the Account Object
	}
	
	// Query the Opportunity using AccountId and build a map of AccountId to the Opportunity record
	// Here the assumption is that One account is tied to only one Opportunity. But if you have multiple opportunities for a single account, the logic must identify the right opportunity
	for(Opportunity opp : [Select Id, Name, AccountId from Opportunity where AccountId = :accountIds]){
		accountOpportunityMap.put(opp.AccountId,opp);
	}
	
	List<MerchOpps__c> mOps = new List<MerchOpps__c>();
	
	// Iterate again to build the Junction Object Records, 
	for(Merchant_Application__c ma : Trigger.new){
		
		if(accountOpportunityMap.containsKey(ma.Account__c)){
			MerchOpps__c mo = new MerchOpps__c(ChildofOpp__c = accountOpportunityMap.get(ma.Account__c).Id, ChildofMA__c = ma.Id);
			mOps.add(mo); // Add the records to the list
		}
	}
	
	// Note that since this trigger is on both After Insert, After Update, and there is no validation to check if the child records already exists for that Opportunity & Merchant Application combination, it inserts child records everytime something gets changed on Merchant Application
	
	insert mOps; // Insert the junction object records. 
	
}


All Answers

logontokartiklogontokartik
I am not sure in the first place if I understand your requirement, 

"So you are trying to create a junction object record whenever either of the parent fields (in your case Opportunity & Merchant_Application__c) are updated?" This doesnt make sense to me. 

A junction object by definition is the bridge between two objects to achieve a many-many relationship. For it to function, it must have both the parent ids present on it.  In your case, to create MerchOpps__c record, you must have both Opportunity Id and Merchant_Application__c Id. 

The trigger you wrote is on Merchant_Application__c, and you are not getting any Opportunity Id in that trigger. And you line of code 

MerchOpps__c M = new
MerchOpps__c         (   Account__c = ma.Account_Name__r.id , ChildofOpp__c = 'ASSIGN_OPPORTUNITY_ID', ChildofMA__c = ma.Id);

is trying to assign a String value to an Id field. which is not right. If you want your code to work, identify the right opportunity to which the record needs to be assigned. 

But even before that, please make sure that your requirement is right


Steve KucklincaSteve Kucklinca
My apologies for lacking clarity. No, the junction object record would only be created if the Merchant_Application__c object was updated, not both parent objects. How would I capture the related Opportunity Id when the Opportunity object does not seem to be referenced anywhere else in the trigger? thus I get required fields missing from Opportunity.
logontokartiklogontokartik
When you said "Related Opportunity Id" what does related mean? I still dont understand your requirement, why would you want to create a new junction object record when one of parents get updated? Also, do you have a opportunity that you want to assign this junction object record to? 
Steve KucklincaSteve Kucklinca
Yes there are opportuities that link to each of the other Master object. Unfortunately Opportunity and Merchant_Application do not connect in any other way but from pulling data to a junction object and I need to create an alert piecing together shared data. Manually generating the junction object is time comsuming and I need an automated process to get the alert to the proper executives
logontokartiklogontokartik
Do you have any rules defined to identify the mappings, like something on the Opportunity that says that it belongs to Merchant_Application (like Name, or any other field?) I mean without any defined rules, its kind of impossible to automate it inside a trigger.
Steve KucklincaSteve Kucklinca
No. But the Parent (controlling) object for Merchant_Application__c is the Account object so they both serve back to the Account.through the Account Name (and further by the Account Id)
logontokartiklogontokartik
Got it, So here is how you write the trigger. I hope this helps. 


trigger MerchOppsRecord on Merchant_Application__c ( after insert, after update){

	Set<Id> accountIds = new Set<Id>();
	Map<Id,Opportunity> accountOpportunityMap = new Map<Id,Opportunity>();
	// Get the parent Account Ids from all the Merchant Application records,
	for(Merchant_Application__c ma : Trigger.new){
		accountIds.add(ma.Account_Name__c); // Assuming Account_Name__c is the fields that maps to the Account Object
	}
	
	// Query the Opportunity using AccountId and build a map of AccountId to the Opportunity record
	// Here the assumption is that One account is tied to only one Opportunity. But if you have multiple opportunities for a single account, the logic must identify the right opportunity
	for(Opportunity opp : [Select Id, Name, AccountId from Opportunity where AccountId = :accountIds]){
		accountOpportunityMap.put(opp.AccountId,opp);
	}
	
	List<MerchOpps__c> mOps = new List<MerchOpps__c>();
	
	// Iterate again to build the Junction Object Records, 
	for(Merchant_Application__c ma : Trigger.new){
		
		if(accountOpportunityMap.containsKey(ma.Account_Name__c)){
			MerchOpps__c mo = new MerchOpps__c(Account__c = ma.Account_Name__c , ChildofOpp__c = accountOpportunityMap.get(Account_Name__c), ChildofMA__c = ma.Id);
			mOps.add(mo); // Add the records to the list
		}
	}
	
	// Note that since this trigger is on both After Insert, After Update, and there is no validation to check if the child records already exists for that Opportunity & Merchant Application combination, it inserts child records everytime something gets changed on Merchant Application
	
	insert mOps; // Insert the junction object records. 
	
}

PS: I handwritten the code based on the above comments, if there are any compile errors or typos please correct them and run. 



Steve KucklincaSteve Kucklinca
Error: Compile Error: Variable does not exist: Account_Name__c at line 22 column 124 This is the latest error I see. and if I were to change to accoundIds, modeled after Put statements accountOpportunityMap.put(opp.AccountId,opp); then the variable after the "," will not exist accountOpportunityMap.get(accountIds, what goes here?)
logontokartiklogontokartik
Can you confirm if you have "Account_Name__c" field on MerchOpps__c object? 
Steve KucklincaSteve Kucklinca
It is there. Does it matter that it is a formula field? If so I so have a tet field Account__cUser-added image
Steve KucklincaSteve Kucklinca
*text fieldUser-added image
Steve KucklincaSteve Kucklinca
the Childof fields are the lookup fields in the Master-Detail relationships
logontokartiklogontokartik
OK. Please try the below, the field  Account_Name__c is formula on Junction, but we were referring it from master object. Anyways, Please try it now

trigger MerchOppsRecord on Merchant_Application__c ( after insert, after update){

	Set<Id> accountIds = new Set<Id>();
	Map<Id,Opportunity> accountOpportunityMap = new Map<Id,Opportunity>();
	// Get the parent Account Ids from all the Merchant Application records,
	for(Merchant_Application__c ma : Trigger.new){
		accountIds.add(ma.Account__c); // Assuming Account__c is the fields that maps to the Account Object
	}
	
	// Query the Opportunity using AccountId and build a map of AccountId to the Opportunity record
	// Here the assumption is that One account is tied to only one Opportunity. But if you have multiple opportunities for a single account, the logic must identify the right opportunity
	for(Opportunity opp : [Select Id, Name, AccountId from Opportunity where AccountId = :accountIds]){
		accountOpportunityMap.put(opp.AccountId,opp);
	}
	
	List<MerchOpps__c> mOps = new List<MerchOpps__c>();
	
	// Iterate again to build the Junction Object Records, 
	for(Merchant_Application__c ma : Trigger.new){
		
		if(accountOpportunityMap.containsKey(ma.Account__c)){
			MerchOpps__c mo = new MerchOpps__c(ChildofOpp__c = accountOpportunityMap.get(ma.Account__c), ChildofMA__c = ma.Id);
			mOps.add(mo); // Add the records to the list
		}
	}
	
	// Note that since this trigger is on both After Insert, After Update, and there is no validation to check if the child records already exists for that Opportunity & Merchant Application combination, it inserts child records everytime something gets changed on Merchant Application
	
	insert mOps; // Insert the junction object records. 
	
}


Steve KucklincaSteve Kucklinca
still seeking an ID? Comppile error Invalid initial expression type for field MerchOpps__c.ChildofOpp__c, expecting: Id at line 22 column 64 seems it wants the Id,variable structure not just ma.Account__c
logontokartiklogontokartik
Sorry. I forgot to put .Id

trigger MerchOppsRecord on Merchant_Application__c ( after insert, after update){

	Set<Id> accountIds = new Set<Id>();
	Map<Id,Opportunity> accountOpportunityMap = new Map<Id,Opportunity>();
	// Get the parent Account Ids from all the Merchant Application records,
	for(Merchant_Application__c ma : Trigger.new){
		accountIds.add(ma.Account__c); // Assuming Account__c is the fields that maps to the Account Object
	}
	
	// Query the Opportunity using AccountId and build a map of AccountId to the Opportunity record
	// Here the assumption is that One account is tied to only one Opportunity. But if you have multiple opportunities for a single account, the logic must identify the right opportunity
	for(Opportunity opp : [Select Id, Name, AccountId from Opportunity where AccountId = :accountIds]){
		accountOpportunityMap.put(opp.AccountId,opp);
	}
	
	List<MerchOpps__c> mOps = new List<MerchOpps__c>();
	
	// Iterate again to build the Junction Object Records, 
	for(Merchant_Application__c ma : Trigger.new){
		
		if(accountOpportunityMap.containsKey(ma.Account__c)){
			MerchOpps__c mo = new MerchOpps__c(ChildofOpp__c = accountOpportunityMap.get(ma.Account__c).Id, ChildofMA__c = ma.Id);
			mOps.add(mo); // Add the records to the list
		}
	}
	
	// Note that since this trigger is on both After Insert, After Update, and there is no validation to check if the child records already exists for that Opportunity & Merchant Application combination, it inserts child records everytime something gets changed on Merchant Application
	
	insert mOps; // Insert the junction object records. 
	
}


This was selected as the best answer
Steve KucklincaSteve Kucklinca
That worked!!!! Any suggestion how to fix naming structure of new record so I don't have the Id string (ma.Id) as the name of the Junction Object record?
Steve KucklincaSteve Kucklinca
And how can I limit creation of the records based on exact value of a field? I have Completed__c field on Merchant Application object and I would only want the JO record created if the field = "Completed"
Steve KucklincaSteve Kucklinca
How do I get code coverage? If I want to deploy in production do I need a test class?