1

I need to populate a record with the values of a parent record before insert. These fields mirror some fields from the parent record, but should be editable by the user (so we can't use formulas).

Because this runs before insert, I'm unable to query the relationship fields the standard way (SELECT ParentObject.Name FROM ... ) because the trigger record ids don't exist yet.

This leaves me with some options:

1- Keep track of the related record ids, query them separately, and do the joins manually later in the code. This requires a lot of boilerplate code so I'm not too excited about it.

2- Do this in a @future method, however I need the field values to be populated before any other logic can run

3- Do it after update, by putting a dummy workflow that fires all the time and re-fires the trigger context. Not too excited either because of recursion.

Are there option/better options?

2
  • Is a Quick Action with Predefined Field Values a possibility to handle in the UI layer rather than in code? – David Reed May 11 '20 at 16:10
  • @DavidReed Thanks. Unfortunately no. These records are most of the time created by other processes and not usually manually. Of course we could hardcode the logic in those other processes but we want to keep the concerns separately i.e "no matter how this record is created, the defaults should be set" – CommonCoreTawan May 11 '20 at 16:11
2

Just use a Map, as I posted in my post years ago, which I call the Aggregate-Query-Update pattern.

Map<Id, Parent> parents = new Map<Id, Parent>();
// Aggregate //
for(Child record: Trigger.new) {
  parents.put(record.ParentId, null);
}
// Query //
parents.putAll([SELECT Field FROM Parent WHERE Id = :parents.keySet());
// Update //
for(Child record: Trigger.new) {
  Parent parent = parents.get(record.ParentId);
  if(parent != null) {
    // Additional handling //
  }
}

Edit: I realize that this is probably what you mean by "option 1"; if you find that you need this a lot, abstract it!

public static Set<Id> getIdsFromRecords(sObject[] records, sObjectField field) {
  Set<Id> values = new Set<Id>();
  for(sObject record: records) {
    values.add((Id)record.get(field));
  }
}

So you can then:

Map<Id, Parent> parents = new Map<Id, Parent>([
  select field from Parent where id = :Utils.getIdsFromRecords(Trigger.new, Child.ParentId)
]);
2
  • Thanks for this. Indeed that's what i was referring to in option 1. To make it worse the fields need to be populated from multiple parents, so I need to keep track of different list of fields per parent object, do multiple queries, and multiple "joins" later on. – CommonCoreTawan May 11 '20 at 16:26
  • 1
    @CommonCoreTawan In most cases, this pattern is still the best choice, unless you're already brushing up against limits. In that case, you could trade some DML for queries, but I would only advise that if you were already far past the SOQL limit that its the only sane option left. – sfdcfox May 11 '20 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.