11

I have some code I'd like to change in a trigger. The issue is that there is a field that is being updated with a prefix plus the value of a field in the object that is an automatic number. The problem is that the auto number is not assigned until after the insert but the field needs to be set before the user sees the values in the form. We're using future calls to handle it because you can't do updates on records that are in the isAfter state. If we use the future calls, there are times the user sees invalid values in the form until after the future call runs and the form is then updated.

How would one avoid this problem?

  • 1
    just out of curiosity, did you try using a formula field (yourPrefix+Name)? – Sam Oct 4 '13 at 16:19
  • Is your prefix standard ? – ManSpan Oct 4 '13 at 16:20
  • Could a workflow handle this? – Mike Chale Oct 4 '13 at 16:25
  • Is the field on the record being updated? – greenstork Oct 4 '13 at 18:40
  • Can't be a formula field because the records are synchronized with an external source both ways. So some of the values are created inside SalesForce and some from the other server. – Robert Harper Oct 4 '13 at 19:45
12

When I've had need for this, I've always used the following pattern, which works out well:

trigger X on Y (after insert, before update) {
    if(Trigger.isAfter && Trigger.isInsert) {
        update Trigger.new.deepClone(true, false, false);
    }
    if(Trigger.isBefore && Trigger.isUpdate) {
        for(Y record: Trigger.new) {
            // Change the value for record
        }
    }
}

You could also prevent recursion with a static field, but this may not be necessary if you use this design.

  • This looks more elegant than what I actually got to work. – Robert Harper Oct 4 '13 at 19:51
  • 1
    This is too clever for me so I'd appreciate a brief explanation of how it works. – Keith C Oct 4 '13 at 22:05
  • Since you can't use Trigger.new or Trigger.old in a DML statement, we use deepClone to make a copy in memory, then call update on it. In the update, it's a normal "before update" trigger. – sfdcfox Oct 5 '13 at 2:40
  • Getting there I think... The pattern makes use of "If the record was updated with workflow field updates, fires before and after triggers one more time (and only one more time)" so that the second time the before trigger runs the auto-numbered field is available to update the other field? (salesforce.com/us/developer/docs/apexcode/Content/…) – Keith C Oct 5 '13 at 10:29
  • 1
    Nothing that nefarious; there's no workflow rules involved. Simply copying the records, and performing an update. – sfdcfox Oct 5 '13 at 15:22
5

You can perform DML operations on records in after insert/after update triggers. You just cannot do it using trigger.old or trigger.new context variables.

You will need to use a static hasRun boolean or something similar in the trigger handler to avoid and infinite recursion in your trigger.

  • Exactly. Using a static Boolean to prevent re-entry into the same trigger code is the way to go. Then just make a deep clone of the record in question to perform updates on it: Contact c = triggerContact.clone(true, true, true, true); Change c. Update c. – Adam Oct 4 '13 at 16:45
3

What I ended up doing is something like this:

Trigger X on Y ( after insert ){
    List<Y> updates = new List<Y>();
    for( Y z : Trigger.new ){
        if( z.Field_To_Change__c == null || z.Field_To_Change__c == '' ){
            Y a = new Y( Id = z.Id );
            a.Field_To_Change__c = 'prefix' + a.AutoNumber__c;
            updates.add( a );
        }
    }
    if( updates.size() > 0 )
        update updates;
}

It works but not as elegant as the deep clone above.

  • This design has the practicality of avoiding the before update event as a trigger, which may make edits marginally faster (though, not enough for anyone to care, I'd imagine). The answer I posted simply allows the flexibility of regenerating the data in case someone modifies it through the data loader, etc. – sfdcfox Oct 4 '13 at 20:29
  • What we are doing is rather simple and your method allows me to remove the future calls on two objects. In one, the user's computer is so slow that they often see the transition between the first save and then after the future call is complete. Doing this in this way removes the need for the future call completely and works faster, especially when caused by background creation in a page controller. – Robert Harper Oct 4 '13 at 20:33

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.