Contents
Triggerの発火タイミングについて
ApexTriggerでは発火のタイミングが下記の種類になります。
- before レコードの処理前
- after レコードの処理後
そしてそれぞれに
- insert
- update
- delete
- undelete(afterのみ)
が加えられて計7通りのタイミングがあります。
書き方は下記の通りです。
trigger トリガ名 on オブジェクト名
(before insert, before update, before delete
after insert, after update, after delete, after undelete) {
//処理を記入
}
処理するタイミングを()内に記入しておかないと発火の取得ができません。
渡されるレコードの種類を理解しておく
トリガの発火のきっかけになったレコードの渡ってくる方法としては
- List型
- Map型
の二種類になります。
書き方としては以下になります。
if ( Trigger.isBefore && Trigger.isInsert) {
system.debug(Trigger.new);
system.debug(Trigger.old);
system.debug(Trigger.newMap);
system.debug(Trigger.oldMap);
}
List | Map |
---|---|
new | newMap |
old | oldMap |
Trigger.の後にそれぞれを指定すると取れます。
それぞれの入ってくる値も違いますので、デバックしてしっかり中身を確認してから、
作成していきましょう。
複数レコードに対応したプログラミングをする
先輩に口すっぱく、トリガは単一のレコードが入ってくるような甘い設計はしてはいけないよと言われました。
salesforceでは、バッチ処理やdateloderなどで何千、何万レコードが一回の処理で入ってくることは
珍しいことではありません。
その時に備えて複数レコードの処理が通るようにしておきましょう。
具体的にはまず下記の2点です。
- SOQLをfor文の中で回さない。
- DML処理をする際はリストなどでまとめて行う。
下記が具体的なソースになります。
SOQLをfor文の中で回さない。
for ( Contact c : Trigger.new ){
Account sample = [SELECT Name From Account Where Contact__c = :c.Id];
}
100以上のレコードが入ってきた場合確実に止まりますので注意です。
トリガに限らずですがSOQLはfor文内で回さないように癖づけておきましょう。
下記のようにすれば同じものをfor文で回すことができます。
List<Account> sampleList = [SELECT Name From Account Where Contact__c IN :Trigger.new]
for ( Account a : sampleList ){
system.debug(a);
}
DML処理をする際はリストなどでまとめて行う。
for ( Contact c : Trigger.new ){
Account sample = new Account(Contact__c = c.Id);
insert sample;
}
この場合もガバナ制限に引っかかる可能性が出てきますので、Listに一件づつ格納したあと、
まとめてインサートしてしまいましょう。
List<Account> insertList = new List<Account>();
for ( Contact c : Trigger.new ){
Account sample = new Account(Contact__c = c.Id);
//insert sample;
insertList.add(sample);
}
insert insertList;
こうすることで一回のDMLで複数レコードを扱えるのでガバナ制限に引っかからないようにコントロールできます。
コメント