こんにちは、アンダーソンです。
今回はApexトリガのベストプラクティスを考えると言うことで、
Apexトリガについて詳しく掘り下げていこうかと思います。
Apexトリガとは
オブジェクトに対してのDML操作をイベントとして受け取り、
プログラム上での判定を入れることができるシステムです。
DML操作は
- 挿入
- 更新
- 削除
- 復元
の4種類で、それぞれDML操作前、後という判定がつきます。
※復元のみ復元後のみ
コードの書き方
Apexトリガは基本的に下記のようなコードになります。
trigger TestTrigger on Test1__c (before insert, after update) {
}
Trigger トリガ名 on オブジェクト名 (起動イベント){}
という流れで作成されますが、この際に
起動イベントには不必要なものは入れないようにしておくべきです。
基本的にここに書いてある起動イベントでトリガが発動するので、
書いてしまっているがために毎回無駄なトリガが動いて、無駄な時間をとってしまうことになってしまいます。
複数イベントの場合は必ず判定を
Apexトリガにはコンテキスト変数が用意されており、
変数を条件判定に使うことができます。
例えば起動イベントをafter insertとafter updateにしている場合、
どちらもafterである事は同じですが、挿入時の処理と、更新時の処理が違うことが
多いと思います。
その際はコンテキスト変数を使います。
if ( Trigger.isInsert ) {
// ここに処理を書く
}
if ( Trigger.isUpdate ) {
// ここに処理を書く
}
これでOKです。ここにあとでbefore insertとかが加わればさらにブロックを拡大して
if ( Trigger.isAfter ) {}とかにしてあげればOKです。
クラスをハンドラーとして呼び出す
ややこしい処理などはApexクラスをハンドラーとして呼び出すという手もあります。
クラスをあらかじめ用意しておき、インスタンス化してイベント判定後に渡すという手法です。
trigger TestTrigger on Test1__c (before insert, after update) {
TestTriggerHandler handler = new TestTriggerHandler();
if ( Trigger.isInsert ) {
handler.afterInsert(Trigger.new);
}
if ( Trigger.isUpdate ) {
handler.afterUpdate(Trigger.new,Trigger.old);
}
}
こんな感じでOKですね。
ハンドラクラス側でイベントにあった名前のメソッドを準備しておけば
わかりやすい実装になると思います。
Mapを効率よく使おう
Apexトリガは大量レコードを想定した作りをしておくのが大前提です。
例えば、1万件のレコードが入ってきたと仮定した際に、どれだけ時間がかかるかです。
レコードは入力規則などのチェックを終えて、トリガに入ってきます。
その後には自動化プロセス系のチェックも待っているので、なるべく早く
トリガを終わらせるようにしておくのがベストプラクティスと言えると思います。
基本的にはMapを使って効率よくレコードを取得します。
例えば、Updateで前後の比較をしたい際に、下記のようなコードだと
タイムアウトする可能性が高くなります。
for ( Account newAcc : newList ) {
for ( Account oldAcc : oldList ) {
if ( newAcc.Id == oldAcc.Id ) {
//何か処理する
}
}
}
1万件×1万件としたらなかなかにやばいことになります。
上記の書き方をMapに変換するだけでかなり効率よく値を取得できます。
for ( Account newAcc : newList ) {
oldAccMap.get(newAcc.Id);
}
これで簡単に新旧比較のロジックができます。
また、当然のことながら、
SOQLをループ内で書かない
と言ったことも処理が多くなるに連れて意外にやってしまいがちなので
是非気にしながら実装していきましょう。
今回はApexトリガについて少し詳しく説明してみました。
結構奥深いトリガ。便利なプログラムですが
間違って使うとガバナ制限に引っかかるなどテクニックの必要なプログラムです。
是非今回の要点を押さえながら、Apexトリガのマスターを目指しましょう!