[salesforce]upsertの時、トリガはどう動く？

# upsertの時、トリガはどう動く？

Apexトリガには、Insert,Update時に前、後でそれぞれ動く処理が書ける事がわかりました。
しかし、DMLには便利なUpsertがあるではないですか。

Upsertというのは、対象レコード（同じIdを持ったレコード）が組織に存在していなければInsertを行い、存在していればUpdateを行うDML操作になります。

Upertが行われたときApexトリガはどう動くのでしょうか。見ていきましょう。

まず、取引先トリガに以下のコードを作成します

```java
trigger Accounttrigger on Account (before update,before insert,after update,after insert) {
    switch on trigger.operationType{
        when BEFORE_INSERT {
            system.debug('before insert');
        }
        when BEFORE_UPDATE {  
            system.debug('before update');
        }
        when AFTER_INSERT {
            system.debug('after insert');
        }
        when AFTER_UPDATE {
            system.debug('after update');
        }
    }
}
```

このトリガが存在している状態で、以下の匿名Apexを実行してみます。
このコードでは既存の取引先レコードを1件取得して、1件新しい取引先を作成、それらをUpsertしています。

```java
List<Account> existAccount = [SELECT Id,Name FROM Account WHERE Id = '0015g000010F5enAAC'];
existAccount.add(new Account(name = 'new Account 001'));
upsert existAccount;
```

結果はどうなったでしょうか。デバッグログを見てみましょう。

```
[4]|DEBUG|before insert
[10]|DEBUG|after insert
[7]|DEBUG|before update
[13]|DEBUG|after update
```

どうやら、Insertのレコードを処理した後にUpdateのレコードを処理するようです。
しかし、1トランザクションで動いているようです。

ここで疑問が生まれます。トリガにてこれらのレコードを一括で処理することはできないのか？です。
例えば、InsertだろうとUpdateだろうとその一覧を名前順に並べたいときとかですかね。

それは可能です。ApexではStaticな値はトランザクション内であればそのままなのでStaticなリストに格納していけば同時に処理する事ができますね。

まずは、ソート可能なクラスと、Staticなそのリストを持つクラスを作成します。

```java
public class ListSortClass {
	static public List<Accounts> staticAccountList;
    
    public class Accounts implements Comparable {
        
    public String name;
    public Account acc;
    
    // Constructor
    public Accounts(Account a) {
        name = a.name;
        acc = a;
    }
    
    // Implement the compareTo() method
    public Integer compareTo(Object compareTo) {
        Accounts compareToAcc = (Accounts)compareTo;
        if (name == compareToAcc.name) return 0;
        if (name > compareToAcc.name) return 1;
        return -1;        
    }
    }
}
```

そしてトリガを書き換えます

```java
trigger Accounttrigger on Account (before update,before insert,after update,after insert) {
       
    switch on trigger.operationType{
        when BEFORE_INSERT {
            // staticなリストの初期化,これは1回だけ処理される場所ならどこでもいいです
    		ListSortClass.staticAccountList = new List<ListSortClass.Accounts>();
            system.debug('before insert');
        }
        when BEFORE_UPDATE {  
            system.debug('before update');
        }
        when AFTER_INSERT {
            system.debug('after insert');
            // ここでリストに詰めます
            for(Account acc : trigger.new){
                ListSortClass.staticAccountList.add(new ListSortClass.Accounts(acc));
            }
        }
        when AFTER_UPDATE {
            system.debug('after update');
            // ここでリストに詰めます
            for(Account acc : trigger.new){
                ListSortClass.staticAccountList.add(new ListSortClass.Accounts(acc));
            }
            // 要素が揃ったのでまずはソートします
            ListSortClass.staticAccountList.sort();
            system.debug('1つのループで処理します');
            for(ListSortClass.Accounts accs : ListSortClass.staticAccountList){
                system.debug('Name : ' + accs.acc.name);
            }
        }
    }
}
```

で、以下のような匿名Apexを発行してみます。
既存の「Edge Communications」という名前の取引先と
新規の「new Account 001」という名前の取引先、
新規の「new Account 002」という名前の取引先、
新規の「new Account 004」という名前の取引先、
新規の「new Account 003」という名前の取引先
を同時にupsertしてみます。

```java
List<Account> existAccount = [SELECT Id,Name FROM Account WHERE Id = '0015g000010F5enAAC'];
existAccount.add(new Account(name = 'new Account 001'));
existAccount.add(new Account(name = 'new Account 002'));
existAccount.add(new Account(name = 'new Account 004'));
existAccount.add(new Account(name = 'new Account 003'));
upsert existAccount;
```

結果は以下のようになりました。ソートもできているし1つのループ内で処理もできていますね。

```
[7]| DEBUG| before insert
[13]| DEBUG|after insert
[10]| DEBUG| before update
[20]| DEBUG| after update
[27]| DEBUG|1つのループで処理します
[29]| DEBUG| Name : Edge Communications
[29]|DEBUG|Name : new Account 001
[29]| DEBUG| Name: new Account 002
[29]| DEBUG| Name : new Account 003
[29]| DEBUG| Name : new Account 004
```

便利だからあまり気にした事がなかったですがupsertってこういう動きなんですね。
勉強になりました。