Memos About Salesforce

Salesforceにハマってたこと!

初心者 SFDCトリガ肥大化(汗) 柔軟性のトリガ 実装論 

こんにちは、管理人の@Salesforce.Zです。

トリガってものがある

オブジェクトごとにトリガが作成できる

ただし、トリガの処理は時間の流れにつれて

だんだん肥大化になってしまい、

メンテナンス性が。。。。。

大好きなトリガについて

今回、やってきた経験を

共有します。

欲しけりゃくれてやる・・・。

探せ!

この世の全てをそこに置いてきた〜笑

目次

トリガは何を、どう使う、実装には?

トリガ 何を?どう使う?

トリガ(Trigger):和語で書くとトリガとトリガー、統一感ない

意味合い:発火するもの、きっかけとなるもの

ITのエンジンニアなら、説明しやすいが

素人なら、理解できるまで、ちょっと時間かかる。

機械を動かすレバーのイメージも個人的ある

アチェンジを例にすると
f:id:jude2016:20180804161145p:plain
そこにギアをチェンジすれば、チェンジ先のギアが動く

このギアがトリガのようなもの、中に自動的に仕事をする

ブロックとなっている。

そして、ギアチェンジのタイミング(きっかけなど)もある

プログラミングの世界では

1:登録(insert)

2:更新(update)

3:削除(delete)

4:マージ(merge)

とうのがきっかけでトリガが動作する。

さらに上記の1〜3まで、

それぞれ、前と後のタイミングがある

マトリックスにすると

通称 プログラミング名称 タイミング区分 組み合わせ効果 案件上の使用頻度
登録 INSERT 1:BEFORE
2:AFTER
1:BEFORE INSERT
2:AFTER INSERT
1:★★★★★
2:★★★★★
更新 UPDATE 1:BEFORE
2:AFTER
1:BEFORE UPDATE
2:AFTER UPDATE
1:★★★★★
2:★★★★★
削除 DELETE 1:BEFORE
2:AFTER
1:BEFORE DELETE
2:AFTER DELETE
1:★★★☆☆
2:★★★☆☆
マージ MERGE 1:BEFORE
2:AFTER
1:BEFORE MERGE
2: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の取引先と商談が親子関係)

商談の金額が変更された場合に、取引先のトリガも動作してしまう

しかし、取引先のレコードではないと取引先のトリガが動作しない実装方法もある

要は自分のデータではないとマイトリガ動作しませんよ

って実装方法もある

これも将来時間ある時に紹介します

まとめ

柔軟性の実装はよく考えた上に実装することが

大事かと思う。

ネストが複雑すぎると、メンテナンス性も落ちる f:id:jude2016:20180804181017p:plain