複雑なSalesforceの入力チェックをApexトリガで行う方法とサンプル

Salesforceの入力チェックは、複数項目の相関チェックや正規表現など、ある程度までなら入力規則でプログラムレスにできます。

しかし、それよりも複雑な場合、たとえば、チェックの際に、関連するレコードの状態を判断するためにSOQL文を発行しないといけないとか、外部のロジックをWebAPIで呼び出すなどは、入力規則だけでは対処できないため、Apexコードを書く必要がありますね。

具体的な手順は、以下の通りです。

Apexトリガで入力チェックを行う手順

入力チェックを行うオブジェクトにトリガを定義

入力チェックを行うのは、多くの場合、オブジェクトを保存する直前になりますから、Apexトリガを作成して、insertやupdateの時に、

入力された値をチェックすればよいですよね。

そのため、対象となるオブジェクトにトリガを作成します。

trigger SampleTrigger on Account (after delete, after insert, after undelete,  after update, before delete, before insert, before update) {
     
    if(Trigger.isInsert || Trigger.isUpdate){
        if(Trigger.isBefore){
            SampleTriggerHandler.checkInputVariables(trigger.new, trigger.OldMap);        
        }    
    }         
}

トリガ内または呼ばれるクラス内で、入力チェックを行う

トリガを定義したら、そのクラスか、そのクラスから呼ばれるクラスで入力のチェックを行います。

ここでのサンプルは、トリガ・ハンドラという別のクラスを呼び出しています。

public class SampleTriggerHandler {
     
    public static void checkInputVariables(List<Account> triggerNew, Map<Id, Account> triggerOldMap){
        System.debug('***checkInputVariables Called***');
         
        for(Account newRecord : triggerNew){
 
      //InsertとUpdateのケース
        if(triggerOldMap==null){
                //insert時
                System.debug('***checkInputVariables insert時***');                
            }else{
                Account oldRecord = triggerOldMap.get(newRecord.Id);
                //update時
                System.debug('***checkInputVariables update時***');        
            }
         
             
            //項目チェック
            Integer singleErrorCnt = 0;
 
            if(String.isEmpty(newRecord.Language__c)){
                singleErrorCnt++;
                newRecord.Language__c.addError('言語は必須です。');
            }
                        
            //デフォルト値セット
            if(newRecord.Country__c==null){
                newRecord.Country__c = 'Japan';
            }
             
            //正規表現でチェック
            Boolean regTest= Pattern.matches('^([0-1][0-9]|[2][0-3]):[0-5][0-9]$', newRecord.Jikan__c);
            if(!regTest){
                singleErrorCnt++;
                newRecord.Jikan__c.addError('時間は「HH:MM」の形式で入力してください。');
            } 
 
            if(singleErrorCnt>0){
                return;
            }           
             
            //マスタ1(Master1__c)からSOQLで検索してデフォルト値をセット
            if(newRecord.Some__c!=null){
                Master1__c ms1 = [select Id, Name, Master1_Name__c from Master1__c where Id =:newRecord.Some__c limit 1];
                newRecord.Some2__c  = ms1.Name;
                newRecord.Some3__c  = ms1.Master1_Name__c;
            }
       
        }
    }
}

少し、無駄なソースも入っていますが、なるべく汎用的に、コピペで使えるようにと思ってのことです。

解説すると、はじめに「InsertとUpdateのケース」があります。

トリガでは、OldとNewの2つのリストが渡ってきます。リスト形式とMap形式が使えますが、私はよくNewをリストで、OldをMap形式で渡します。

それは、Newをリストの拡張For文のループで回し、それに対応するOldの値をMapでNewのIdをキーに取得するやり方が簡単だからです。

で、Oldがnullであれば、新規作成時(Insert)だと判断できます。

「Salesforceのトリガでのoldとnewの使い方」も参考に。

Salesforceのトリガでのoldとnewの使い方Salesforceのトリガでのoldとnewの使い方

また、それ以降は入力チェックです。

Newに入っている値が、画面から入力された値なので、それに対して、チェックを行っています。

また、必要であれば、値を上書きしてあげると「デフォルト値セット」などが出来ます。

エラーメッセージのセットの仕方

入力チェックエラーの場合、メッセージを返す必要がありますよね。

その場合には、「newRecord.Language__c.addError(‘言語は必須です。’);」のように、項目に対してメッセージをセットします。

その後、returnすれば、レコードは保存されずに、入力画面に戻り、セットしたエラーメッセージが表示されるというわけです。