I am attempting to write a trigger and I relatively new to both Salesforce and Object oriented programming and I am struggling, so any help would be appreciated!
Task Description:
I have two custom objects, Employee, and Position Associate. Position Associate is an object that creates a mapping and record between an employee and a respective position that they hold. I am attempting to write a trigger, that runs any time a Position Associate is created or updated, that takes three fields, Training Start, Training End, and Home Study Start, and populates it with data from the employee object, from the employee that is mapped to the Position Associate record in question. This must be a trigger as opposed to a making the field a lookup value. So while that may be simpler, it is not an option in this scenario
Current Behavior: While I am not getting any errors, after a record is updated, the fields still remain blank.
Code:
trigger MapDatesPA on Position_Employee__c(after insert, after update) {
// Create trigger that runs when a new record is inserted or when a record is updated that maps the employee fields
// of Home Study Start Date, Training Start and End Dates to Position Associate Object
// Prevent Iterative Loop
if (checkRecursive.runOnce()) {
Map<Id, Employee__c> pm = new Map<Id, _Employee__c>();
Set<Id> empIds = new Set<Id>();
for (Position_Employee__c posEmp : Trigger.new) {
if (posEmp.Employee__c != null) {
empIds.add(posEmp.Employee__c);
}
}
for (Employee__c emp : [
SELECT Id, HOME_STUDY_START_DATE__c, Training_Start_Date__c, Training_End_Date__c
FROM Employee__c
WHERE Id IN :empIds
]) {
if (pm.containsKey(emp.Id)) {
pm.put(emp.id, emp);
}
}
for (Position_Employee__c posemp : Trigger.New) {
if (pm.containsKey(posemp.Id)) {
posemp.Training_Start_Date__c = pm.get(posemp.Id).Training_Start_Date__c;
posemp.Training_End_Date__c = pm.get(posemp.Id).Training_End_Date__c;
posemp.Home_Study_Start_Date__c = pm.get(posemp.Id).HOME_STUDY_START_DATE__c;
}
}
}
}
Best Answer
That
checkRecursive.runOnce()
that you have worries me. I get the feeling that it's just checking a static boolean variable. If that's the case, and you happen to insert or update more than 200 records at a time, your trigger would only perform its work on the first 200 records.Even though you say this must be a trigger, what you have right now really could be accomplished with some very simple formula fields (assuming that
Employee__c
on yourPosition_Employee__c
object is either a lookup relationship field or a master-detail relationship field). If there's any room for you to push back on the "use a trigger" requirement you've been given, this is something I'd fight for. Using 3 formula fields is going to be faster to develop, and doesn't require any tests to be written.If you still insist on doing this with a trigger, some things to note:
before
trigger context (before insert
orbefore update
) and are modifying a value on a record contained in eithertrigger.new
ortrigger.newMap
. Modifying a value on a record in either of those will cause the new value to be saved without the need for DMLPosition_Employee__c
and you're trying to make changes toPosition_Employee__c
records)Beyond that, you have two main issues in your current logic.
The first issue is your second loop
As Mark Pond pointed out, that
if()
statement is wrong. You're saying "if this map already contains this key, then put this record into the map". If you put asystem.debug(pm.size());
right after that for loop, it'll be guaranteed to show you a "0" (meaning the map is empty).You could fix that, but the entire for loop is unnecessary. Salesforce gives us a way to put the result of a query (which is a
List<SObject>
) into aMap<Id, SObject>
in a single line.pm.putAll([SELECT Id, <other fields here> FROM Employee__c WHERE Id IN :empIds]);
The second issue is your third loop
Different SObjects in Salesforce have different Ids. The first 3 characters of an Id indicate what SObject it is. '001' indicates it's an
Account
, '500' indicates it's aCase
, and so on.The point here is that your
pm
map uses the Id ofEmployee__c
records as the key, and this map will never contain any keys forPosition_Employee__c
records.Your
Position_Employee__c
records do contain an Id for yourEmployee__c
records, just not in theId
field. Instead, that's in theEmployee__c
field (which you used to build theempIds
set which allowed you to query for Employees).Everywhere that you have
posemp.Id
in this third loop, you should instead be usingposemp.Employee__c
.You could also save yourself some typing by fetching the
Employee__c
record from the map once, storing the result in a variable, and then using that variable to get at the field values.example