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
J BengelJ Bengel 

related records in trigger

We have two custom objects, Trade and Program Trade, that we are using in an apprenticeship development app.

Trade is a lookup table containing various codes, descriptions, and training details.
Program Trade is an instance of a trade within an apprenticeship program, and (in theory) sets some of its fields to default values using the corresponding fields in Trade. Those values may be modified by the end user after the fact, but by giving them default values based on the Trade, we hope to limit the number of mising and invalid values entered on the record.
Program Trade contains a lookup on the Name field in Trade to establish the reference between the two objects.
If I execute the following query in the Developr console:
SELECT Name,Sponsor__r.Name, Sponsored_Program__r.Name,Training_Type__c,Trades__r.Name, Trades__r.Training_Type__c
FROM Program_Trade__c
WHERE Sponsored_Program__r.Name != Null AND Sponsor__r.Name != Null
LIMIT 10

Name	Sponsor__r.Name	Sponsored_Program__r.Name	Training_Type__c	Trades__r.Name	Trades__r.Training_Type__c
Why?	Really Kool Gizmos	Really Kool Gizmos-Apprenticeship	Time Based	Computer Programmer	Time Based
Painter	Really Kool Gizmos	Really Kool Gizmos-Apprenticeship	Time Based	Painter (Professional and Kindred)	Time Based
Combination Welder	Really Kool Gizmos	Really Kool Gizmos-Apprenticeship	Competency Based	Welder, Combination	Competency Based
Reactor Fixer	Duke Harris	Chernobyl Avoidance		Powerhouse Mechanic	Time Based
The first three were set manually, which is why they have values in them. The fourth was the test case I used for this trigger:
trigger setTradeDefaults on Program_Trade__c(before insert, before update) {
    for (Program_Trade__c pt : Trigger.new){
		System.debug('Trigger setTradeDefaults initial value of pt.Training_Type__c:' + pt.Training_Type__c);
		System.debug('Trigger setTradeDefaults initial value of pt.Trades__r.Training_Type__c:' + pt.Trades__r.Training_Type__c);
        if (String.isBlank(pt.Training_Type__c)){
            pt.Training_Type__c = pt.Trades__r.Training_Type__c;
            System.debug('Trigger setTradeDefaults assigned pt.Training_Type__c the value :' + pt.Training_Type__c);
        }
    }
}
And the debug log shows these three entries when I saved the program trade with the Training Type field left empty:
12:47:20:033 USER_DEBUG [3]|DEBUG|Trigger setTradeDefaults initial value of pt.Training_Type__c:null
12:47:20:034 USER_DEBUG [4]|DEBUG|Trigger setTradeDefaults initial value of pt.Trades__r.Training_Type__c:null
12:47:20:034 USER_DEBUG [7]|DEBUG|Trigger setTradeDefaults assigned pt.Training_Type__c the value :null
This happened at both insert and update, and the debug trace tels me that (a) the trigger fired and (b) the if condition passed.  But what it doesn't tell me is why pt.Trades__r.Training_Type__c is empty.  My best guess (which I fear is the case) is that in order to have visibilty into the lookup record beyond the fields expressly translated on the Program Trade record, I either need to run a SOQL query within the body of the trigger (which seems excessive for the purpose) OR create formula field(s) on Program Trade to make those value(s) accessible directly on the Program Trade record (which doesn't seem like it would be any more efficient than the query solution) and use those to set the default value(s) of the actual data fields.

Neither solution is especially appealing, so I'm hoping that in my novice-ness there's just something I haven't learned yet that would be a better idea. In a perfect world, I'd do this translation client side, and display the default values in real time, but that doesn't appear to be an option -- at least in the Lightning UI. I've seen recommendaiotns for using Workflow rules for tasks like this, but there seems to be a divide on whether those are a good idea these days. Sounds like Workflow in general is being phased out, which doesn't bode well for future proofing in my app.


 
Best Answer chosen by J Bengel
TechingCrewMattTechingCrewMatt
Hello. You are correct, to accomplish this in a trigger will require another SOQL query. You can get the Id of the parent record in the trigger context variables, but nothing else.

I think your best bet is to use Process Builder to populate those fields. The best practice for Process Builder and Triggers is to have one per Object so that you can determine the order of execution. If you have two Triggers on the same Object, you can't guarantee the order of execution.

Good luck,
Matt

All Answers

TechingCrewMattTechingCrewMatt
Hello. You are correct, to accomplish this in a trigger will require another SOQL query. You can get the Id of the parent record in the trigger context variables, but nothing else.

I think your best bet is to use Process Builder to populate those fields. The best practice for Process Builder and Triggers is to have one per Object so that you can determine the order of execution. If you have two Triggers on the same Object, you can't guarantee the order of execution.

Good luck,
Matt
This was selected as the best answer
J BengelJ Bengel
Thanks. That's what I was afraid of. Hadn't considered Process Builder, but it's worth looking at (assuming my teammate hasn't alrewayd got one running against this object.) Took a look at Workflow Rules, just to satisfy my curiousity, and discovered that because I'm trying to update a picklist field here, my only available options are to pick a hard value from the list.  There appears to be no way to go between objects in this case. The only one I'd ever done to date was one to concatenate the name fields on Contact and load Chosen Full Name with the result. That was using fields withint the same object though.