Apex

保存時のBefore・Afterトリガと入力規則の順序

検証用オブジェクトと入力規則、Before・Afterトリガを用意し、保存時に各処理が動く順番を確認します。Beforeトリガは入力規則より先に動きます。

2023.02.10

なぜ順番を知る必要があるか

Beforeトリガの中で「入力規則さえ後で通れば安全」と思って処理を書くと、実際には違反したままのデータに対してもBeforeトリガが動いてしまいます。逆にAfterトリガは、必須項目チェックと入力規則の両方を通って保存が成功した後にしか動きません。この前後関係を知らないと、想定した処理が想定したタイミングで動きません。

保存時の実行順序

Salesforceの公式リファレンス「トリガーと実行の順序」では、レコード保存時の処理が次の順で並んでいます。

順番処理
1システム入力規則(必須項目の有無など)
2保存前に実行するよう設定されたレコードトリガフロー
3Beforeトリガ
4入力規則(カスタムのバリデーションルール)
5データベースへの保存(コミットはまだしない)
6Afterトリガ
7割り当てルール
8自動応答ルール
9ワークフロールール
10保存後に実行するよう設定されたレコードトリガフロー
11積み上げ集計項目の再計算
12データベースへのコミット

Beforeトリガ(3)は、入力規則(4)より先に動きます。必須項目チェック(1)より後ではありますが、カスタムの入力規則の合否はまだ分かっていません。Afterトリガ(6)は、入力規則を通って保存された(5)後に動きます。

検証用オブジェクトを準備する

  1. カスタムオブジェクトを作る

    オブジェクトマネージャで表示ラベル「testObject1」、オブジェクト名「testObject1」を作成します。API参照名は自動的にtestObject1__cになります。

  2. レコード名の項目を自動採番に変える

    標準の「testObject1名」項目をテキストから自動採番へ変更します。表示形式はTO1-{0000}、開始番号は1にします。

  3. 必須のカスタム項目を作る

    表示ラベル「testText」、項目名「testText」、データ型テキスト(255文字)で作成し、「必須項目」にチェックを入れます。項目レベルセキュリティは全プロファイルに公開し、全ページレイアウトへ追加します。

  4. 入力規則を作る

    ルール名「Within10characters」、エラー条件式LEN(testText__c) > 10、エラーメッセージ「文字数が10以内にしてください。」、エラー表示場所は項目「testText」にします。

カスタムオブジェクトtestObject1の定義の詳細画面。API参照名が表示されている
作成したカスタムオブジェクトの定義です。API参照名が自動でtestObject1__cになっている点を見てください。
レコード名項目testObject1名の編集画面。データ型が自動採番、表示形式はTO1-{0000}
レコード名の項目を自動採番へ変えるところです。データ型と表示形式TO1-{0000}の欄を見てください。
カスタム項目testTextの定義の詳細画面。データ型テキスト、必須項目にチェックが付いている
必須のカスタム項目testTextです。一般的なオプションの「必須項目」にチェックが入っていることを確認してください。
入力規則Within10charactersの詳細画面。エラー条件数式とエラーメッセージが並ぶ
入力規則の中身です。エラー条件数式がLEN(testText__c) > 10、エラー表示場所がtestTextになっている点を見てください。

トリガとハンドラの実装

before・afterのどちらのタイミングで動いたかを、デバッグログへ書き出すだけのシンプルな作りにします。

testObject1Trigger.trigger

trigger testObject1Trigger on testObject1__c (before insert, after insert) {
    testObject1TriggerHandler handler = new testObject1TriggerHandler();
    if (Trigger.isBefore) {
        handler.beforeInsert(Trigger.new);
    }
    if (Trigger.isAfter) {
        handler.afterInsert(Trigger.new);
    }
}

beforeとafterの両方で、実行されたタイミングをログへ書き出すだけのトリガです

testObject1TriggerHandler.cls

public with sharing class testObject1TriggerHandler {
    public void beforeInsert(List<testObject1__c> newRecords) {
        System.debug('before insert: ' + newRecords.size());
    }

    public void afterInsert(List<testObject1__c> newRecords) {
        System.debug('after insert: ' + newRecords.size());
    }
}

beforeInsertとafterInsertが呼ばれたことをデバッグログへ記録します

trigger本文とハンドラクラスを「Before用」「After用」で2組用意すると、同じクラス名のファイルが2つできてしまい、両方を同時にデプロイできません。ここでは1本のトリガと1つのハンドラで、beforeとafterの両方を扱います。

保存したときの挙動

testTextへ入れる値を変えて保存すると、次のように動きます。

testTextの入力必須項目チェックBeforeトリガ入力規則保存Afterトリガ
空白エラー実行されない到達しないされない実行されない
11文字(規則に違反)通過実行されるエラーされない実行されない
10文字(規則を満たす)通過実行される通過される実行される
新規testObject1の編集画面。testTextの入力欄が空で、必須を示す赤い印が付いている
Beforeトリガだけを有効にして試したときの新規作成画面です。testTextに必須の赤い印が付いていることを見てください。
空欄のまま保存したときのエラー画面。「エラー: 値を入力してください」が表示されている
testTextを空のまま保存した結果です。システム入力規則(必須項目チェック)で止まっていることを見てください。
新規testObject1の編集画面。testTextに11文字の12345678901を入力している
入力規則に違反する11文字を入れたところです。このあと保存して、Beforeトリガが動くかどうかを確かめます。
11文字で保存したときのエラー画面。「文字数が10以内にしてください。」と赤字で出ている
同じ保存の画面側の結果です。入力規則のエラーメッセージが項目testTextの下に出ていることを見てください。
新規testObject1の編集画面。testTextに10文字の1234567890を入力している
今度は入力規則を満たす10文字を入れたところです。必須項目チェックも入力規則も通るので、このまま保存に成功します。
保存されたレコードTO1-0002の詳細画面。testTextに1234567890が入っている
保存に成功したレコードです。自動採番のTO1-0002が採番され、testTextの値が入っていることを見てください。

Beforeトリガは、11文字を入れた行でも実行されています。必須項目チェックの後、入力規則より前に位置するためです。Afterトリガは、10文字を入れて保存が成功した行でしか実行されていません。

新規testObject1の編集画面。testTextの入力欄が空で、必須を示す赤い印が付いている
ここからはAfterトリガだけを有効にして、同じ3通りをもう一度試します。まずは空欄のまま保存します。
空欄のまま保存したときのエラー画面。「エラー: 値を入力してください」が表示されている
空欄での保存結果です。必須項目チェックで止まるため、Afterトリガまで到達しないことを確かめます。
新規testObject1の編集画面。testTextに11文字の12345678901を入力している
入力規則に違反する11文字を入れたところです。必須項目チェックは通りますが、入力規則で保存が止まります。
11文字で保存したときのエラー画面。「文字数が10以内にしてください。」と赤字で出ている
11文字で保存した結果です。ここでも保存まで到達しないので、Afterトリガのログは出ないことを見てください。
新規testObject1の編集画面。testTextに10文字の1234567890を入力している
最後に入力規則を満たす10文字を入れて保存します。3通りのうち、保存が成功するのはこの条件だけです。
保存されたレコードTO1-0003の詳細画面。testTextに1234567890が入っている
Afterトリガが動いたときに保存されたレコードです。採番がTO1-0003へ進んでいることを見てください。
Beforeトリガの中で保存を止めたい条件があるなら、入力規則の結果を待たずに、自分でaddError()を呼んで止める必要があります。入力規則はBeforeトリガより後に評価されるので、Beforeトリガの実行そのものは止まりません。

ここで間違えやすい

間違い何が起きるか
Beforeトリガの中でレコードが保存済みだと思い込むまだ保存前です。insertならIdは空のままです
Afterトリガは必ず動くと思い込む必須項目チェックか入力規則でエラーになると、Afterトリガまで到達しません
同じ名前のクラスを2つ用意するコンパイルエラーになり、デプロイできません
保存前後のフローとトリガの順序を無視する保存前フローはBeforeトリガより先、保存後フローはAfterトリガより後に動きます

確認した環境

  • 2026年9月 / Salesforce Summer '26(APIバージョン67.0)時点の公式リファレンス「トリガーと実行の順序」で、保存時の処理の並びを確認しています

まとめ

  • 保存時は、システム入力規則→保存前フロー→Beforeトリガ→入力規則→保存→Afterトリガ→割り当てルール→自動応答ルール→ワークフロールール→保存後フロー→積み上げ集計→コミットの順で進みます
  • Beforeトリガは入力規則より先に動きます。規則違反のデータに対しても実行されます
  • Afterトリガは、必須項目チェックと入力規則の両方を通って保存が成功した後にしか動きません
  • Beforeトリガの中で保存を止めたいときは、入力規則を待たずaddError()で自分で止めます
  • 同じ名前のクラスを2つ用意すると、デプロイできません

参考:当時の画面

記事を最初に書いた当時の画面です。いまの手順と違うところは、各画像の説明に書いています。

開発者コンソールの実行ログ。beforeInsertのstartとendのデバッグ行が並ぶ
11文字で保存したときの実行ログです。入力規則で止まる行でもBeforeトリガが動いていることを見てください。
開発者コンソールの実行ログ。beforeInsertのstartとendのデバッグ行が並ぶ
10文字で保存したときの実行ログです。11文字のときと同じようにBeforeトリガが動いていることを見てください。
開発者コンソールの実行ログ。afterInsertのstartとendのデバッグ行が並ぶ
10文字で保存したときの実行ログです。Afterトリガは保存が成功したこの1回だけ動いていることを見てください。

Salesforceの導入・運用についてご相談ください

導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。