Apexトリガー
ApexトリガーはSalesforce開発の中核ですが、同時に最も事故が多い領域です。
理由はシンプルで、「適当に書いても一応動く」からです。
しかし実務ではそれが致命傷になります。
トリガーの本質
トリガーは「イベント駆動」です。
発火タイミング:
・before insert
・after insert
・before update
・after update
・before delete
・after delete
ここでまず重要な理解:
👉 before = 値変更用 / after = 関連処理用
アンチパターン(これやると終わる)
① トリガーに全部書く
trigger BadTrigger on Account (before insert) {
for (Account acc : Trigger.new) {
// ロジック全部ここ
}
}
問題:
・再利用不可
・テストしにくい
・肥大化する
② トリガー複数作成
→ 実行順序が保証されない
→ バグの温床
👉 原則:1オブジェクト1トリガー
正しい設計:トリガーフレームワーク
基本構成:
trigger AccountTrigger on Account (
before insert, before update,
after insert, after update
) {
AccountTriggerHandler handler = new AccountTriggerHandler();
if (Trigger.isBefore) {
if (Trigger.isInsert) handler.beforeInsert(Trigger.new);
if (Trigger.isUpdate) handler.beforeUpdate(Trigger.new, Trigger.oldMap);
}
if (Trigger.isAfter) {
if (Trigger.isInsert) handler.afterInsert(Trigger.new);
}
}
public class AccountTriggerHandler {
public void beforeInsert(List<Account> newRecords) {
// ロジック
}
public void beforeUpdate(List<Account> newRecords, Map<Id, Account> oldMap) {
// 差分処理
}
public void afterInsert(List<Account> newRecords) {
// 関連レコード作成など
}
}
差分検知が超重要
更新時は「何が変わったか」を見ないと事故る。
if (acc.Status__c != oldMap.get(acc.Id).Status__c) {
// 状態変化時のみ処理
}
これをやらないと:
👉 無限更新ループ
👉 無駄なDML
👉 パフォーマンス劣化
再帰防止(これ知らないと死ぬ)
トリガー内で更新 → またトリガー発火 → 無限ループ
対策:
public class TriggerControl {
public static Boolean isRunning = false;
}
if (TriggerControl.isRunning) return;
TriggerControl.isRunning = true;
Bulk対応(必須)
Salesforceは常に「複数レコード前提」
NG:
for (Account acc : Trigger.new) {
insert new Contact(Name='test');
}
OK:
List<Contact> contacts = new List<Contact>();
for (Account acc : Trigger.new) {
contacts.add(new Contact(Name='test'));
}
insert contacts;
まとめ
・トリガーは薄く
・ロジックはクラスへ
・差分検知は必須
・Bulk前提で書く
・再帰防止を忘れるな
