トリガ基礎

# 1. Apexトリガとは
Apexトリガとは、各オブジェクトの作成、更新、削除のタイミングを拾って処理を実行できる仕組みです。
# 2. トリガの起動タイミング
トリガには「beforeトリガ」と「afterトリガ」があります。
両者の違いは、レコードがDBに保存される前に実行されるか、後に実行されるかということです。
◆トリガーイベント（起動タイミング）
・ before insert
・ before update
・ before delete
・ after insert
・ after update
・ after delete
・ after undelete
## 2.1 beforeトリガ
レコードがDBに保存される前に起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/866e7a85-1474-0a3b-740a-b38419d39c5c.png)
## 2.2 afterトリガ
レコードがDBに保存される後に起動（※コミットはまだされていない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/0c27315b-b528-6109-0bb0-a1130c179ddb.png)

# 3. トリガ構文
```
Trigger トリガ名 on オブジェクト名  (トリガイベント) {
    //code_block 
}
```
# 4. トリガコンテキスト変数
◆Trigger.isExecuting
現在のコンテキストがApexトリガから呼び出されている場合に、Trueを返します。
◆Trigger.isInsert
レコードの新規作成処理によるApexトリガの場合に、Trueを返します。
◆Trigger.isUpdate
レコードの更新処理によるApexトリガの場合に、Trueを返します。
◆Trigger.isDelete
レコードの削除処理によるApexトリガの場合に、Trueを返します。
◆Trigger.isUndelete
レコードの復元処理によるApexトリガの場合に、Trueを返します。
◆Trigger.isBefor
Before triggerの場合に、trueを返します。
◆Trigger.isAfter
After triggerの場合に、trueを返します。
◆Trigger.new
Sobjectレコードの新しいバージョンのリストを返します。
◆Trigger.old
Sobjectレコードの古いバージョンのリストを返します。
◆Trigger.newmap
Sobjectレコードの新しいバージョンのマップを返します。キーはID項目になります。
◆Trigger.oldmap
Sobjectレコードの古いバージョンのマップを返します。キーはID項目になります。
◆Trigger.size
新旧両方のトリガの呼び出し内のレコードの合計数を返します。
◆Trigger.Operationtype
現在の操作に対応する system.triggeroperation 種別の列挙値を返します。system.triggeroperation 列挙値の有効な値は、before_insert、before_update、before_delete、after_insert、after_update、after_delete、after_undelete です。トリガの種類に基づいて、異なるプログラミングロジックを使用する場合は、switch ステートメントを使用して、一意のトリガ実行列挙状態の異なる順列を指定することを検討します。
## 4.1 トリガイベントとトリガコンテキスト変数 まとめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/349bd106-8665-8c2d-9347-1967c2973d73.png)
## 4.2 【before insert】と【after insert】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/efaf1f81-c604-b7c9-0ba4-44d7064acc0f.png)
## 4.3 【before update】と【after update】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/b0d25cac-b8f4-3f7b-7b56-cbc04da22956.png)
## 4.4 【before delete】と【after delete】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/e2fffe02-349c-5798-329c-9762e0c12b4c.png)
## 4.5 【after undelete】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/620c86a5-bfdb-faf4-3868-263c9f167474.png)

# 5. トリガまとめ
## ①beforeトリガとafterトリガの違い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1835427/17eab4c6-d3a5-ea7d-0c79-655a96d5d2c4.png)

## ②beforeトリガとafterトリガの使い分け
◆insert/updateされたレコードを、dbに保存される前に操作したい。➡ 「beforeトリガ」
◆入力規則のチェックより前に処理を実行したい。 ➡ 「beforeトリガ」
◆dbに保存された後のレコードにアクセスしたい。 ➡ 「afterトリガ」
◆他レコードの参照/主従関係項目として設定したい。 ➡ 「afterトリガ」



# 6.トリガDemo
　①コンテキスト変数中身確認（beforトリガ、afterトリガ）
　②after insert例
　③after update例
　④before delete例
　⑤after undelete例
　
## 6.1 トリガDemo　確認用資材①
### TriggerDemo(Trigger) 
```Apex:(TriggerDemo)
trigger TriggerDemo on Account (before insert,before update,before delete,after insert,after update,after delete,after undelete) {
    //コンテキスト変数isBefore確認
    if(Trigger.isBefore){
        system.debug('BeforeTrigger【コンテキスト変数確認】処理開始---------------------------------------------------');  
        system.debug('コンテキスト変数isBefore: '+ Trigger.isBefore);  
        //AccountHandleクラスの呼び出し
        AccountHandler.AccountHandler();
        system.debug('BeforeTrigger【コンテキスト変数確認】処理完了---------------------------------------------------');  
    }

    //コンテキスト変数isAfter確認
    if(Trigger.isAfter){
        system.debug('AfterTrigger【コンテキスト変数確認】処理開始---------------------------------------------------');  
        //AccountHandleクラスの呼び出し
        AccountHandler.AccountHandler();
        system.debug('AfterTrigger【コンテキスト変数確認】処理完了---------------------------------------------------');  
    }
    
    //--------------------------------------------------------------------------------------------------
    // insertトリガ 確認
    // afterInsertの場合
    if(Trigger.isAfter && Trigger.isInsert){
        AccountHandler.AccountHandlerAfterInsert();
    }
    //--------------------------------------------------------------------------------------------------
    // updateトリガ 確認
    // afterUpdateの場合
    if(Trigger.isAfter && Trigger.isUpdate){
        AccountHandler.AccountHandlerAfterUpdate(Trigger.newMap,Trigger.oldMap);
    }
    //--------------------------------------------------------------------------------------------------
    //Deleteトリガ 確認
    //Before Delete
    if(Trigger.isBefore && Trigger.isDelete){
        AccountHandler.AccountHandlerAfterDelete();
    }
    //--------------------------------------------------------------------------------------------------
    //UnDeleteトリガ 確認
    //After UnDelete
    if(Trigger.isAfter && Trigger.isUndelete){
        AccountHandler.AccountHandlerAfterUnDelete();
    }

}
```

## 6.2 トリガDemo　確認用資材②
### AccountHandler(Apex) 
```Apex:(AccountHandler)
public with sharing class AccountHandler {
    public static void AccountHandler() {

        //triggerから呼び出しの場合
        if(Trigger.isExecuting){
            system.debug('【triggerクラスから呼び出し】AccountHandler処理開始---------------------------------------------------');  

                system.debug('トリガからの実行である、Trigger.isExecuting: '+ Trigger.isExecuting);
                //コンテキスト変数isExecuting確認
                system.debug('コンテキスト変数【isExecuting】: '+ Trigger.isExecuting); 
                //コンテキスト変数isInsert確認
                system.debug('コンテキスト変数【isInsert】: '+ Trigger.isInsert);  
                //コンテキスト変数isUpdate確認
                system.debug('コンテキスト変数【isUpdate】: '+ Trigger.isUpdate);  
                //コンテキスト変数isDelete確認
                system.debug('コンテキスト変数【isDelete】: '+ Trigger.isDelete); 
                //コンテキスト変数isUndelete確認
                system.debug('コンテキスト変数【isUndelete】: '+ Trigger.isUndelete); 
                //コンテキスト変数isBefore確認
                system.debug('コンテキスト変数【isBefore】: '+ Trigger.isBefore);  
                //コンテキスト変数isAfter確認
                system.debug('コンテキスト変数【isAfter】: '+ Trigger.isAfter);   
                //コンテキスト変数new確認
                system.debug('コンテキスト変数【new】: '+ Trigger.new); 
                //コンテキスト変数old確認
                system.debug('コンテキスト変数【old】: '+ Trigger.old); 
                //コンテキスト変数newMap確認
                system.debug('コンテキスト変数【newMap】: '+ Trigger.newMap); 
                //コンテキスト変数oldMap確認
                system.debug('コンテキスト変数【oldMap】: '+ Trigger.oldMap); 
                //コンテキスト変数size確認
                system.debug('コンテキスト変数【size】: '+ Trigger.size);  
                //コンテキスト変数operationType確認
                system.debug('コンテキスト変数【operationType】: '+ Trigger.operationType); 
            system.debug('【triggerクラスから呼び出し】AccountHandler処理完了---------------------------------------------------');  
        //trigger以外から呼び出しの場合
        }else{
            system.debug('【triggerクラス以外から呼び出し】AccountHandler処理開始---------------------------------------------------');  
            system.debug('トリガ以外からの実行である、Trigger.isExecuting: '+ Trigger.isExecuting); 
            //コンテキスト変数isExecuting確認
            system.debug('コンテキスト変数【isExecuting】: '+ Trigger.isExecuting); 
            //コンテキスト変数isInsert確認
            system.debug('コンテキスト変数【isInsert】: '+ Trigger.isInsert);  
            //コンテキスト変数isUpdate確認
            system.debug('コンテキスト変数【isUpdate】: '+ Trigger.isUpdate);  
            //コンテキスト変数isDelete確認
            system.debug('コンテキスト変数【isDelete】: '+ Trigger.isDelete); 
            //コンテキスト変数isUndelete確認
            system.debug('コンテキスト変数【isUndelete】: '+ Trigger.isUndelete); 
            //コンテキスト変数isBefore確認
            system.debug('コンテキスト変数【isBefore】: '+ Trigger.isBefore);  
            //コンテキスト変数isAfter確認
            system.debug('コンテキスト変数【isAfter】: '+ Trigger.isAfter);   
            //コンテキスト変数new確認
            system.debug('コンテキスト変数【new】: '+ Trigger.new); 
            //コンテキスト変数old確認
            system.debug('コンテキスト変数【old】: '+ Trigger.old); 
            //コンテキスト変数newMap確認
            system.debug('コンテキスト変数【newMap】: '+ Trigger.newMap); 
            //コンテキスト変数oldMap確認
            system.debug('コンテキスト変数【oldMap】: '+ Trigger.oldMap); 
            //コンテキスト変数size確認
            system.debug('コンテキスト変数【size】: '+ Trigger.size);  
            //コンテキスト変数operationType確認
            system.debug('コンテキスト変数【operationType】: '+ Trigger.operationType); 
            system.debug('【triggerクラス以外から呼び出し】AccountHandler処理完了---------------------------------------------------');  
        }
    }
    //--------------------------------------------------------------------------------------------------
    // insertトリガ 確認
    public static void AccountHandlerAfterInsert() {
        // 挿入リスト（取引先責任者） 
        List<Contact> contactList = new List<Contact>();
        system.debug('afterInsert Trigger確認処理開始--------------------------------------------------- ');
        system.debug('afterUpdate【Trigger.old】中身：' + Trigger.old );
        system.debug('afterUpdate【Trigger.new】中身：' + Trigger.new );
        system.debug('afterUpdate【Trigger.oldMap】中身：' + Trigger.oldMap );
        system.debug('afterUpdate【Trigger.newMap】中身：' + Trigger.newMap );
        system.debug('afterUpdate【operationType】中身：'+ Trigger.operationType); 
        List<Account> accList = Trigger.new;

        // Trigger.newはリストであるため、1件づつ処理行う
        for(Account acc : accList){
            system.debug('afterInsert【Trigger.new】のN件目：' + acc );
            // 登録用[取引先責任者]変数N件
            Contact con = new Contact();
            // [取引先責任者.AccountId]に[取引先.ID]を設定する
            con.AccountId = acc.Id;
            // [取引先責任者.LastName]に[取引先.Name + 取引先責任者]を設定する
            con.LastName = acc.Name + ' 取引先責任者';
            // [取引先責任者.AccountId]に[110番]を設定する
            con.Phone = '110';
            // 挿入リスト（取引先責任者）に追加する
            contactList.add(con);
        }
        
        if(contactList.size() > 0 ){
            // 挿入リスト（取引先責任者）が0件以上であれば、登録処理を行う
            system.debug('【挿入リストcontactList（取引先責任者）】中身：' + contactList );
            system.debug('afterInsert Trigger確認処理完了--------------------------------------------------- ');
            insert contactList;
        }
    }
    //--------------------------------------------------------------------------------------------------
    // updateトリガ 確認
    public static void AccountHandlerAfterUpdate(Map<id,Account> newAccoutMap, Map<id,Account> oldAccoutMap) {
        system.debug('afterUpdate Trigger確認処理開始--------------------------------------------------- ');
        system.debug('afterUpdate【Trigger.old】中身：' + Trigger.old );
        system.debug('afterUpdate【Trigger.new】中身：' + Trigger.new );
        system.debug('afterUpdate【Trigger.oldMap】中身：' + Trigger.oldMap );
        system.debug('afterUpdate【Trigger.newMap】中身：' + Trigger.newMap );
        system.debug('afterUpdate【operationType】中身：'+ Trigger.operationType); 
        
        // Map<id,Account> newAccoutMap =  Trigger.newMap;
        // Map<id,Account> oldAccoutMap =  Trigger.oldMap;
        // newAccoutMap.values()=Trigger.new 

        // 挿入リスト（商談） 
    	List<Opportunity> opptList = new List<Opportunity>();
        // newAccoutMapは複数件であるため、1件づつ処理行う
        for(Account acc : newAccoutMap.values()){
            //商談これからDB入るsobject.Rating 商談これからDB入るsobject.Rating
            if(newAccoutMap.get(acc.Id).Rating != oldAccoutMap.get(acc.Id).Rating){
            	Opportunity opp = new Opportunity();
                opp.AccountId = acc.Id;
                opp.Name = acc.Name + '商談';
                opp.StageName ='Prospecting';
                opp.CloseDate = System.today();
                // 挿入リスト（商談）に追加する
                opptList.add(opp);
            }
        }
        
        if(opptList.size() > 0 ){
            // 挿入リスト（商談）が0件以上であれば、登録処理を行う
            system.debug('【挿入リストoppList（商談）】中身：' + opptList );
            system.debug('afterUpdate Trigger確認処理完了--------------------------------------------------- ');
            insert opptList;
        }
    }
    //--------------------------------------------------------------------------------------------------
    // Deleteトリガ 確認
    public static void AccountHandlerAfterDelete() {
        system.debug('beforeDelete Trigger確認処理開始--------------------------------------------------- ');
        system.debug('beforeDelete【Trigger.old】中身：' + Trigger.old );
        system.debug('beforeDelete【Trigger.new】中身：' + Trigger.new );
        system.debug('beforeDelete【Trigger.oldMap】中身：' + Trigger.oldMap );
        system.debug('beforeDelete【Trigger.newMap】中身：' + Trigger.newMap );
        system.debug('beforeDelete【operationType】中身：'+ Trigger.operationType);
    
        List<Account> accList = Trigger.old;

        for(Account acc : accList){
            if(acc.Active__c == 'Yes'){
                acc.addError('この取引先が有効であるため、削除出来ません');
            }
        }
        system.debug('beforeDelete Trigger確認処理完了--------------------------------------------------- ');
    }
    //--------------------------------------------------------------------------------------------------
    // UnDeleteトリガ 確認
    public static void AccountHandlerAfterUnDelete() {
        system.debug('AfterUnDelete Trigger確認処理開始--------------------------------------------------- ');
        system.debug('AfterUnDelete【Trigger.old】中身：' + Trigger.old );
        system.debug('AfterUnDelete【Trigger.new】中身：' + Trigger.new );
        system.debug('AfterUnDelete【Trigger.oldMap】中身：' + Trigger.oldMap );
        system.debug('AfterUnDelete【Trigger.newMap】中身：' + Trigger.newMap );
        system.debug('AfterUnDelete【operationType】中身：'+ Trigger.operationType);
    
        List<Account> accList = Trigger.new;
        // 挿入リスト（商談） 
    	List<Opportunity> opptList = new List<Opportunity>();
        // newAccoutMapは複数件であるため、1件づつ処理行う
        for(Account acc : accList){
            Opportunity opp = new Opportunity();
            opp.AccountId = acc.Id;
            opp.Name = acc.Name + '復元取引先商談';
            opp.StageName ='Prospecting';
            opp.CloseDate = System.today();
            // 挿入リスト（商談）に追加する
            opptList.add(opp);
        }
        
        if(opptList.size() > 0 ){
            // 挿入リスト（商談）が0件以上であれば、登録処理を行う
            system.debug('【挿入リストoppList（商談）】中身：' + opptList );
            system.debug('AfterUnDelete Trigger確認処理完了--------------------------------------------------- ');
            insert opptList;
        }
    }
}

```