[SalesForce] Updating a field with a value from parent during insert trigger

I would appreciate some best practice advice here –

I have an insert trigger to populate a field in the record being inserted into a custom object with the value of a field in the parent object.

From other posts I learned that trigger.new cannot see any related fields.

Taking the value from a formula field on my custom object would normally be a choice but maximum number of object references has been reached due to high number of formula fields so I can't create another.

So I need to look up the value with SOQL and store it in a map with the Id of the record being inserted.

Which means that my before insert trigger must now be an after insert in order to know the Id.

If I query into a map and then update the field on the record being inserted I then need to issue an update DML statement, so in order to populate my field I need an insert and an update.

Seems inefficient – is that the only way?

Thanks,
Mike.

Best Answer

Actually you don't need to do that first insert to get the object's id. You need the id of the parent to do the query, and you should have that since it should be populated in the look-up field. I would do something like this:

// use a before insert trigger
// loop through trigger new, putting parent ids into a set<Id>
// query for parent objects, then use that list as argument in map constructor
// loop through trigger new again, get parent object from map, set field value

Update

I wanted to add a working example here to better illustrate my answer above. Note that if you are working with a look-up relationship, you should check to make sure that there actually is a parent record before trying to get a value from it.

trigger Contact on Contact (before insert){

    if (trigger.isBefore){
        if (trigger.isInsert){
            SetContactField.setAccountName(trigger.new);
        }
    }

}

public class SetContactField{

    public static void setAccountName(list<Contact> TriggerNew){

        list<Id> AccountIds = new list<Id>();

        for (Contact c : TriggerNew){
            AccountIds.add(c.AccountId);
        }

        map<Id,Account> RelatedAccounts = new map<Id,Account>([SELECT Id, Name FROM Account WHERE Id IN :AccountIds]);

        for (Contact c : TriggerNew){
            Account RelatedAccount = RelatedAccounts.get(c.AccountId);
            if (RelatedAccount == NULL){  // In a master detail relationship, this record is guaranteed to exist. 
                c.AccountName__c = NULL;
            } else {
                c.AccountName__c = RelatedAccount.Name;
            }
        }

    }

}