2

When using Apex Database.DMLOptions for invoking standard Lead Assignment Rules, is it sane to use beforeUpdate instead of afterupdate? And is it sane to do this in non-future apex vs (as opposed to) @future apex? These questions are phrased below in more detail.

Trigger code

Trigger leadTrigger on Lead (before update){ //see Question 2
        Set<Id> leadsToAssign = new Set<Id>();
    for(Lead lead : (List<Lead>)Trigger.new){
            //optional conditions for populating leadsToAssign
              leadsToAssign.add(Lead.Id);
          }
            if(system.isfuture()) return; // avoid recursion scenario of the future method update
            leadutil.autoassign(leadsToAssign);
      }
}

Apex Class

public class leadutil {
  @future //see Question 1
  public static void autoassign(set<id> ids) {
    lead[] leads = [select id from lead where id in :ids];
    if(leads.isempty()) return;
    database.dmloptions dmo = new database.dmloptions();
    dmo.assignmentruleheader.usedefaultrule = true;
    for(lead l:leads)
      l.setoptions(dmo);
    update leads;
  }
}

Question 1:

What issues might I be overlooking in trying to do this synchronously (instead of in @future)? I don't think I need higher limits so if i can avoid using a @future call then i will; I care more about giving the users a "real-time" experience so that they can see the result of Lead Assignment without having to wait for a @future call to finish. Why are so many people in favor of doing this in a @future call?

Question 2:

What issues might I be overlooking when I put the logic in a beforeUpdate trigger context as opposed to an after update context?

3 Answers 3

3

You can't realistically trigger an update during an update (before or after, doesn't matter, you'll get a recursive update error), and DMLOptions won't affect the current transaction. You will necessarily need to use the @future method (or Queueable, if you desire) in order to run the assignment rules. Note that under light system load, your @future method will likely run immediately after the main transaction, before the page even loads. Either way, you should prefer simply having the "Use Active Assignment Rules" on the page, set as default, and for API calls, use the AssignmentRuleHeader instead of an Apex Trigger.

As for "before or after", it doesn't really matter, as far as the database is concerned, but general rule of thumb is to perform validations and pre-commit record changes in "before" triggers, and post-commit record changes (such as re-submitting a record for DML, or updating parent or child records), queuing external callouts, and so on, in "after" triggers. This is mostly a matter of optimization in most cases where you're not forbidden from doing stuff. For example, you can't change a record's fields in "after" triggers, so you need to use a "before" trigger, but you can call future methods any time you like, so it's not imperative that you use an "after" trigger, although I'd recommend it.

4
  • I thought best practice for validating was in "after update" so that you ensure all changes have occurred before saying a record is not valid to save to the database. Thoughts? Sep 19, 2017 at 4:49
  • 2
    @techbusinessman I find that in the majority of cases, you want to validate as early as possible to minimize resource use (particularly CPU, SOQL, and DML statements). The practice of waiting until a record has been committed before validating is logically faulty; if you're waiting until after "all changes have occurred", you're really validating your own logic, not the user's input. After all, the user can't modify the data from the time they click "save" to the time the record is committed. Validation is generally about validating user input.
    – sfdcfox
    Sep 19, 2017 at 5:25
  • Thanks for the explanation! I really like the blog post @Andrew Fawcett put out pushing for using the after phase to ensure nothing can change before doing validation: andyinthecloud.com/2015/04/19/… Sep 19, 2017 at 18:17
  • @techbusinessman The example in that post is contrived and very unusual in typical orgs. Yes, there are times when you might have to resort to validating after commit, but usually you want to validate before the commit or before you even modify the data. For example, in the scenario in that post, what happens when the user types in 42, and then gets an error that the value was not 42? They have literally no way to fix the problem or even understand what happened.
    – sfdcfox
    Sep 19, 2017 at 19:21
1

The issue with synchronous is that it is an operation that can be performed through the User Interface.

The documentation is clear here:

DMLOptions settings take effect only for record operations performed using Apex DML and not through the Salesforce user interface

Hence, you need to do DML on the Lead to set DmlOptions.

As for beforeUpdate/afterUpdate - this is more a matter of convention with other triggers you might have -- updates to objects should be done in afterXXX trigger contexts.

3
  • cropredy - is it imperative to do the DmlOptions in a @ future context? Why not use a non-future context? And when you say updates to objects should be done in afterXXX trigger contexts, why not in a beforeUpdate context? Are you talking only about explicit DML Update calls? I'm asking because i thought beforeUpdate was also a good option for assigning field values to the records passing through the beforeUpdate context. I imagine the main decision factor is where in the trigger execution stack (beforeUpdate or AfterUpdate) you want the value-setting to happen . Would you agree? Sep 18, 2017 at 23:34
  • @SFDC_peter - before update is an implicit DML, not an explicit DML. You might try an afterUpdate where you requery the Lead and then do DML on it w/ dmlOptions set. I remember trying this a long time ago and had issues so went to future. You will need to worry about recursion as any DML on Lead will cause the triggers to re-execute
    – cropredy
    Sep 19, 2017 at 0:15
  • interesting @cropredy, and thanks for your helpful comment. If you recall the issues you had with doing it in a non-future call please share. Sep 19, 2017 at 1:11
0

I found this answer helpful too, stolen from this article: enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .