[salesforce]トリガーテンプレート

By |1月 7, 2011|salesforce, |


トリガ開発の無用な手間を省くテンプレートが作られていました。

A Simple Trigger Template for Salesforce

トリガ開発は単純にみえて、相当はまるポイントが多い開発です。Salesforceの開発において一番はまりやすいかもしれません。このトリガーテンプレートは、以下のようなトリガの問題を解決するために作られました。

  • Force.com IDEのトリガ作成ウィザードでは提供されない、トリガ内での大量レコード処理への対処
  • (isInsert, isBefore, etc…)のわかりづらい7つのトリガ起動イベントの可読性とメンテ性の向上
  • Trigger.old Trigger.Newが、それぞれ利用可能な条件の間違い防止
  • 非同期メソッドの実装

これらはいずれもトリガ開発を行った方なら一度は直面するポイントだと思われます。これらの問題の間違いを防ぎ素早く実装するために以下のようなテンプレート内容となっています。(Accountオブジェクトのトリガの例。対象オブジェクトは適時修正して利用してください。)

AccountTrigger.trigger
このトリガで、全てのトリガイベントのキャッチを行い、そこから実行するイベント制御をトリガーハンドラークラスに渡しています。

[java]
trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
AccountTriggerHandler handler = new AccountTriggerHandler(Trigger.isExecuting, Trigger.size);
if(Trigger.isInsert && Trigger.isBefore){
handler.OnBeforeInsert(Trigger.new);
}
else if(Trigger.isInsert && Trigger.isAfter){
handler.OnAfterInsert(Trigger.new);
AccountTriggerHandler.OnAfterInsertAsync(Trigger.newMap.keySet());
}
else if(Trigger.isUpdate && Trigger.isBefore){
handler.OnBeforeUpdate(Trigger.old, Trigger.new, Trigger.newMap);
}
else if(Trigger.isUpdate && Trigger.isAfter){
handler.OnAfterUpdate(Trigger.old, Trigger.new, Trigger.newMap);
AccountTriggerHandler.OnAfterUpdateAsync(Trigger.newMap.keySet());
}
else if(Trigger.isDelete && Trigger.isBefore){
handler.OnBeforeDelete(Trigger.old, Trigger.oldMap);
}
else if(Trigger.isDelete && Trigger.isAfter){
handler.OnAfterDelete(Trigger.old, Trigger.oldMap);
AccountTriggerHandler.OnAfterDeleteAsync(Trigger.oldMap.keySet());
}
else if(Trigger.isUnDelete){
handler.OnUndelete(Trigger.new);
}
}
[/java]

AccountTriggerHandler.cls
こちらのトリガーハンドラークラスで、それぞれのイベントに応じた処理を実装します。各メソッドの中に自分で実行したい処理を記述することになります。

[java]
public with sharing class AccountTriggerHandler {
private boolean m_isExecuting = false;
private integer BatchSize = 0;
public AccountTriggerHandler(boolean isExecuting, integer size){
m_isExecuting = isExecuting;
BatchSize = size;
}
public void OnBeforeInsert(Account[] newAccounts){
//Example usage
for(Account newAccount : newAccounts){
if(newAccount.AnnualRevenue == null){
newAccount.AnnualRevenue.addError(‘Missing annual revenue’);
}
}
}
public void OnAfterInsert(Account[] newAccounts){
}
@future public static void OnAfterInsertAsync(Set<ID> newAccountIDs){
//Example usage
List<Account> newAccounts = [select Id, Name from Account where Id IN :newAccountIDs];
}
public void OnBeforeUpdate(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> accountMap){
//Example Map usage
Map<ID, Contact> contacts = new Map<ID, Contact>( [select Id, FirstName, LastName, Email from Contact where AccountId IN :accountMap.keySet()] );
}
public void OnAfterUpdate(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> accountMap){
}
@future public static void OnAfterUpdateAsync(Set<ID> updatedAccountIDs){
List<Account> updatedAccounts = [select Id, Name from Account where Id IN :updatedAccountIDs];
}
public void OnBeforeDelete(Account[] accountsToDelete, Map<ID, Account> accountMap){
}
public void OnAfterDelete(Account[] deletedAccounts, Map<ID, Account> accountMap){
}
@future public static void OnAfterDeleteAsync(Set<ID> deletedAccountIDs){
}
public void OnUndelete(Account[] restoredAccounts){
}
public boolean IsTriggerContext{
get{ return m_isExecuting;}
}
public boolean IsVisualforcePageContext{
get{ return !IsTriggerContext;}
}
public boolean IsWebServiceContext{
get{ return !IsTriggerContext;}
}
public boolean IsExecuteAnonymousContext{
get{ return !IsTriggerContext;}
} }
[/java]