こんにちは、管理人の@Salesforce.Zです。
トリガってものがある
オブジェクトごとにトリガが作成できる
ただし、トリガの処理は時間の流れにつれて
だんだん肥大化になってしまい、
メンテナンス性が。。。。。
大好きなトリガについて
今回、やってきた経験を
共有します。
欲しけりゃくれてやる・・・。
探せ!
この世の全てをそこに置いてきた〜笑
目次
トリガは何を、どう使う、実装には?
トリガ 何を?どう使う?
トリガ(Trigger):和語で書くとトリガとトリガー、統一感ない
意味合い:発火するもの、きっかけとなるもの
ITのエンジンニアなら、説明しやすいが
素人なら、理解できるまで、ちょっと時間かかる。
機械を動かすレバーのイメージも個人的ある
ギアチェンジを例にすると そこにギアをチェンジすれば、チェンジ先のギアが動く
このギアがトリガのようなもの、中に自動的に仕事をする
ブロックとなっている。
そして、ギアチェンジのタイミング(きっかけなど)もある
プログラミングの世界では
1:登録(insert)
2:更新(update)
3:削除(delete)
4:マージ(merge)
とうのがきっかけでトリガが動作する。
さらに上記の1〜3まで、
それぞれ、前と後のタイミングがある
マトリックスにすると
通称 | プログラミング名称 | タイミング区分 | 組み合わせ効果 | 案件上の使用頻度 |
---|---|---|---|---|
登録 | INSERT | 1:BEFORE2:AFTER | 1:BEFORE INSERT2:AFTER INSERT | 1:★★★★★2:★★★★★ |
更新 | UPDATE | 1:BEFORE2:AFTER | 1:BEFORE UPDATE2:AFTER UPDATE | 1:★★★★★2:★★★★★ |
削除 | DELETE | 1:BEFORE2:AFTER | 1:BEFORE DELETE2:AFTER DELETE | 1:★★★☆☆2:★★★☆☆ |
マージ | MERGE | 1:BEFORE2:AFTER | 1:BEFORE MERGE2:AFTER MERGE | 1:★☆☆☆☆2:★☆☆☆☆ |
トリガ実装に関する考慮すべき事項
- 一回発火し動作したら、止まらないになってしまう可能性あるか
要はいつ動作、いつ停止、他の操作によって動作してしまうか
制御厳密ではない場合、他の操作によって、動いて、ガバナー制限に要注意
なぜトリガを使うか、プロセスビルダもあるから
複数レコードが来ることを前提に実装しているか
よくあるのが、1レコードをイメージしたロジック
標準トリガテンプレ
シンプルにトリガクラスに処理実装する
salesforceが日本にきたばかりの時に
みんなのやり方、現在、ほぼ、こんな実装する人がいない
ではないかと思っている
この標準トリガはsalesforceの取引先ってテーブルに対して
実装するトリガ、取引先のデータを登録・更新・削除毎に動作する
クラスとなっている
if文とコンテキスト変数でイベント・タイミングを分岐し
必要な処理を実装する
trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) { if(Trigger.isInsert && Trigger.isBefore){ //Trigger.new:コンテキスト変数、ここでは取引先のリストが入っている //取引先のデータを登録する前の処理 }else if(Trigger.isInsert && Trigger.isAfter){ //処理 }else if(Trigger.isUpdate && Trigger.isBefore){ //処理 }else if(Trigger.isUpdate && Trigger.isAfter){ //処理 }else if(Trigger.isDelete && Trigger.isBefore){ //処理 }else if(Trigger.isDelete && Trigger.isAfter){ //処理 }else if(Trigger.isUnDelete){ //処理 } }
最近トリガテンプレ
最近というか、salesforceに詳しい人がトリガクラスに処理
を入れず、トリガから詳細処理のクラスを呼ぶような実装をする
トリガクラスは機械操作のレバーの機能をするだけ
ハンドラークラスでは、詳細処理を機能する
これは、日本流かなと思っています。
海外には、まだ他の実装方法が流行っている
今回、紹介しません
1:トリガクラス(AccountTrigger)
trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) { boolean isExecuting = false; integer batchSize = 0; //トリガの詳細処理をするクラス AccountHandlerTrigger handler = new AccountHandlerTrigger(isExecuting, batchSize); if(Trigger.isInsert && Trigger.isBefore){ handler.onBeforeInsert(Trigger.new); }else if(Trigger.isInsert && Trigger.isAfter){ handler.onAfterInsert(Trigger.new, Trigger.newMap); }else if(Trigger.isUpdate && Trigger.isBefore){ handler.onBeforeUpdate(Trigger.old, Trigger.oldMap,Trigger.new, Trigger.newMap); }else if(Trigger.isUpdate && Trigger.isAfter){ handler.onAfterUpdate(Trigger.old, Trigger.oldMap,Trigger.new, Trigger.newMap); }else if(Trigger.isDelete && Trigger.isBefore){ handler.onBeforeDelete(Trigger.old, Trigger.oldMap); }else if(Trigger.isDelete && Trigger.isAfter){ handler.onAfterDelete(Trigger.old, Trigger.oldMap); }else if(Trigger.isUnDelete){ handler.onBeforeDelete(Trigger.new, Trigger.newMap); } }
2:トリガハンドラクラス(AccountHandlerTrigger)
public class AccountHandlerTrigger { private boolean m_isExecuting = false; private integer BatchSize = 0; public AccountHandlerTrigger(boolean isExecuting, integer size){ m_isExecuting = isExecuting; BatchSize = size; } /** * Event Acion:Before Insert */ public void onBeforeInsert(Account[] newAccounts){ } /** * Event Acion:After Insert */ public void onAfterInsert(Account[] newAccounts, Map<ID, Account> accountMap){ } /** * Event Acion:After Insert 同期処理 */ @future public static void onAfterInsertAsync(Set<ID> newAccountIDs){ //ユースケース例 List<Account> newAccounts = [select Id, Name from Account where Id IN :newAccountIDs]; } /** * Event Acion:Before Update */ public void onBeforeUpdate(Account[] oldAccounts, Map<ID, Account> oldAccountMap, Account[] updatedAccounts, Map<ID, Account> newAccountMap){ //ユースケース例 Map<ID, Contact> contacts = new Map<ID, Contact>( [select Id, FirstName, LastName, Email from Contact where AccountId IN :newAccountMap.keySet()] ); } /** * Event Acion:After Update */ public void onAfterUpdate(Account[] oldAccounts, Map<ID, Account> oldAccountMap, Account[] updatedAccounts, Map<ID, Account> newAccountMap){ } /** * Event Acion:After Update 同期処理 */ @future public static void OnAfterUpdateAsync(Set<ID> updatedAccountIDs){ //ユースケース例 List<Account> updatedAccounts = [select Id, Name from Account where Id IN :updatedAccountIDs]; } /** * Event Acion:Before Delete */ public void onBeforeDelete(Account[] accountsToDelete, Map<ID, Account> accountMap){ } /** * Event Acion:After Delete */ public void onAfterDelete(Account[] deletedAccounts, Map<ID, Account> accountMap){ } /** * Event Acion:After Delete 同期処理 */ @future public static void onAfterDeleteAsync(Set<ID> deletedAccountIDs){ } /** * Event Acion:Undelete */ public void onUndelete(Account[] restoredAccounts){ } }
柔軟性の高いトリガテンプレ
柔軟性の高いトリガはケースバイケースだが
E.X. * 同じオブジェクトのトリガだが、レコードタイプによる
詳細内容が違い、ハンドラークラスから
さらにレコードタイプ別のクラスとか
次回紹介するが、しばらく待ちください!
自分のレコード操作だけ動作するトリガテンプレ
取引先のトリガは普段、
商談に対して、金額の積み上げ集計をしている
(salesforceの取引先と商談が親子関係)
商談の金額が変更された場合に、取引先のトリガも動作してしまう
しかし、取引先のレコードではないと取引先のトリガが動作しない実装方法もある
要は自分のデータではないとマイトリガ動作しませんよ
って実装方法もある
これも将来時間ある時に紹介します
まとめ
柔軟性の実装はよく考えた上に実装することが
大事かと思う。
ネストが複雑すぎると、メンテナンス性も落ちる