ワークフロー再評価での実行順序

トリガとワークフローを併用した時の実行順序

レコードを保存した時に、トリガやワークフローなどの実行順序は以下の通りとなります。

  1. システムの入力規則
  2. beforeトリガ
  3. カスタム入力規則
  4. afterトリガ
  5. 割り当てルール
  6. 自動応答ルール
  7. ワークフロールール
  8. プロセス
  9. エスカレーションルール
  10. 積み上げ集計
  11. データベースのコミット

これは、割と基本的な内容で、上級デベロッパーの試験でなくても問われます。
上級デベロッパーの試験で考慮しないといけないのは、ワークフロールールが再評価された時のケースについても留意しなければいけません

ワークフロールール再評価ありの場合の実行順序

ワークフロールールが再評価された場合、ワークフロールールのアクション後に再度、beforeトリガ、afterトリガが実施されます

  1. システムの入力規則
  2. beforeトリガ
  3. カスタム入力規則
  4. afterトリガ
  5. 割り当てルール
  6. 自動応答ルール
  7. ワークフロールール
  8. beforeトリガ(2回目)
  9. afterトリガ(2回目)
  10. プロセス
  11. エスカレーションルール
  12. 積み上げ集計
  13. データベースのコミット

実際に検証してみる

理屈は分かったものの、本当にこの通りになるか確認するために、実際にやってみました。

まずは簡易的なオブジェクトの作成から。名前にセンスを感じないが気にしないでね。

オブジェクト定義

オブジェクト名

トリガ検証(Toriken__c)

カスタム項目
ラベル API参照名 データ型
Num Num__c 数値(18、0)

ワークフロー・項目自動更新

次にワークフロールールと項目自動更新の作成します。項目自動更新は単純にNumに数値を1足すだけです。
もちろん「項目変更後にワークフロールールを再評価する」にチェックします。
有効化も忘れずに。

トリガ

そしてトリガも書いて有効化します。
beforeトリガで数値を1足す処理を入れてるのと、デバッグログを仕込む処理を入れます。もう、トリガに直接処理を書いちゃいますが。

trigger Toriwork on Toriken__c (before insert, before update, after insert, after update) {
    List<Toriken__c> tList = Trigger.New;
    
    String msg = Trigger.isBefore ? 'before:' : 'after:';
    
    if(Trigger.isBefore){
        for(Toriken__c t : tList){
            t.Num__c = t.Num__c + 1;
        }
    }
    if(Trigger.isBefore){
        for(Toriken__c t : tList){
            System.debug(msg + String.valueOf(t.Num__c));
        }
    }
}

入力規則

念のため、入力規則も仕込んでおきます。
これは、2回目のトリガ後に入力規則が働かないことを確認するために入れています。

これで準備完了!
Numを1として登録します。

結果はこうなりました。

before:2
after:2
before:4
after:4


このことから、1回目のafterの後にワークフローが動き、2回目のbeforeトリガの後には入力規則が動いていないことが分かります

一応、Numを2として登録するとやっぱり入力規則エラーが出ます。

仕込んだログはこのように最初のbeforeトリガで止まっていることが分かります。

before:3

再評価後は入力規則のチェックはしません

再評価後のトリガを実行させないためには

static変数を使ってフラグ判定すれば、意図的にスキップすることができます。

static変数を含んだフラグを持ったクラス

public class FirstFlg { 
    // beforeトリガ実行フラグ
    public static boolean beforeExecute = false;
    // afterトリガ実行フラグ
    public static boolean afterExecute = false;
}

トリガもフラグを参照するように少し修正しました。赤字の部分を追加し、再評価後の2回目のトリガは実行しないようにしています。

trigger Toriwork on Toriken__c (before insert, before update, after insert, after update) {
    List<Toriken__c> tList = Trigger.New;
    
    String msg = Trigger.isBefore ? 'before:' : 'after:';
    
    if(Trigger.isBefore){
        if(!FirstFlg.beforeExecute){
            for(Toriken__c t : tList){
                t.Num__c = t.Num__c + 1;
            }
            // before実行フラグを立てて、再評価後に更新しないようにする
            FirstFlg.beforeExecute = true;
        }
    }
    if(Trigger.isBefore){
        if(!FirstFlg.afterExecute){
            for(Toriken__c t : tList){
                System.debug(msg + String.valueOf(t.Num__c));
            }
            // after実行フラグを立てて、再評価後に更新しないようにする
            FirstFlg.afterExecute = true;
        }
    }
}

まとめ

いかがでしたでしょうか。
基本的な内容ではあるんですが、上級試験だと、基本ケースと基本ケースを組み合わせたケースもよく出題されるので、落ち着いて考えればできると思います。
今回の押さえておくべきポイントは以下の通りです。

  • ワークフロー再評価後はbeforeトリガ、afterトリガが再実行される
  • 再評価後の入力規則はチェックしない
  • 再評価後に意図的にトリガを実行しない場合は、static変数を使う

コメント

  1. ヒョウ より:

    「再評価後のトリガを実行させないためには」の例で、
    if(Trigger.isBefore){
    if(!FirstFlg.afterExecute){
    for(Toriken__c t : tList){
    System.debug(msg + String.valueOf(t.Num__c));
    }
    // after実行フラグを立てて、再評価後に更新しないようにする
    FirstFlg.afterExecute = true;
    }
    }
    の部分は、
    for(Toriken__c t : tList){
    System.debug(msg + String.valueOf(t.Num__c));
    }
    これで終わりではないですか?2つのifがいらないではないですか?