芯が強い人になるESTJ-A

# 【ApexTrigger】トリガ処理で標準画面にエラーメッセージを表示させる処理を入れる

IT開発 Tags: 无标签 阅读: 178

トリガの対象のレコードに対してエラーメッセージを付加することで、
beforeトリガとafterトリガの間で実行されるDML操作をせず、
エラーメッセージを表示させる方法です。

beforeTrigger のロジックの中で
Trigger.new の一部のレコードに以下の処理をします。

Map<Id, sObject > newMap = Trigger.new;
sObject record = newMap.values();
sr.addError( '表示するエラーメッセージ' );

■ApexPages 名前空間に addMessage(message) する方法
以下の方法で ApexPages 名前空間にメッセージを付加させても
うまくはいかないようです。

下記の方法は、Visualforce のコントローラとして Apex を
記述した場合に使える方法です。

大体の挙動は以下を参照してください。

ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.CONFIRM,'概要メッセージです' ,'詳細メッセージです' ) );
ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.ERROR,'概要メッセージです' ,'詳細メッセージです' ) );
ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.FATAL,'概要メッセージです' ,'詳細メッセージです' ) );
ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.INFO,'概要メッセージです' ,'詳細メッセージです' ) );
ApexPages.addMessage( new ApexPages.Message(ApexPages.Severity.WARNING,'概要メッセージです' ,'詳細メッセージです' ) );

大体の見え方
http://vaindespair.blogspot.jp/2011/03/blog-post.html
http://blog.livedoor.jp/volvic_beer/archives/52430269.html
Message クラス
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_pages_message.htm

参考
sObject クラス
https://developer.salesforce.com/docs/atlas.ja-jp.208.0.apexcode.meta/apexcode/apex_methods_system_sobject.htm#apex_System_SObject_addError

ApexPages クラス
https://developer.salesforce.com/docs/atlas.ja-jp.200.0.apexcode.meta/apexcode/apex_methods_system_apexpages.htm?search_text=ApexPages

Trigger 的标准结构如下:

trigger Trigger名字 on 对象名字 (触发事件) {
    // Do something
}

Trigger 类必须以关键字 “trigger” 开始,然后是此 Trigger 的名字。接下来是 “on” 关键字,然后是 Trigger 对应的对象的名字。对象名字后面的括号中写入触发 Trigger 的事件。

Trigger 的触发事件分为以下几种:

before insert:插入数据之前
before update:更新数据之前
before delete:删除数据之前
after insert:插入数据之后
after update:更新数据之后
after delete:删除数据之后
after undelete:恢复数据之后

trigger HelloWorldTrigger on Account (before insert, before update) {
    System.debug('Hello World!');
}

这个 Trigger 在每一个 Account 对象插入或更新之前执行。

如果执行了如下代码:

Account a = new Account(Name='test');
insert a;

a.Name = 'test2';
update a;

Trigger 的预设变量
Trigger 类可以使用一些系统预设的变量,来辅助实现一些公共的操作。

Trigger.New 和 Trigger.Old
Trigger.New 和 Trigger.Old 是两个预定义变量,可以用于每一个 Trigger 类中。前者代表了即将被插入、更新的数据,后者代表了更新之前、删除之前的数据。它们可能包含一条数据,也可能包含一组数据,取决于触发 Trigger 时的状态。

要注意的是,Trigger.New 不存在于 delete 操作中,因为删除之后就没有数据了。而 Trigger.Old 不存在于 insert 操作中,因为插入数据之前是没有数据的。

在下面的代码中,我们可以为每一条即将被插入数据库的 Account 数据定义 Description 字段的值。

trigger HelloWorldTrigger on Account (before insert) {
    for(Account acc : Trigger.New) {
        acc.Description = 'New account desc';
    }
}

布尔值变量
除了 Trigger.New 和 Trigger.Old,系统还提供了一系列的布尔值变量,用于标志 Trigger 或数据的状态。

最常用的有:

isInsert:是否是 insert 操作
isUpdate:是否是 update 操作
isDelete:是否是 delete 操作
isBefore:是否是操作之前
isAfter:是否是操作之后
在下面的代码中,我们可以定义对于不同的操作和不同的时机,写入不同的日志记录。

trigger HelloWorldTrigger on Account (before insert, after insert, before delete) {
    if(Trigger.isInsert) {
        if(Trigger.isBefore) {
            System.debug('This is before insert');
        } else if(Trigger.isAfter) {
            System.debug('This is after insert');
        }
    } else if(Trigger.isDelete) {
        System.debug('This is delete');
    }
}

Trigger 中的错误处理

trigger OppyMaxAmountTrigger on Opportunity (before insert, before update) {
    for(Opportunity opp : Trigger.New) {
        if(opp.amount < 1000) {
            opp.addError('Amount should not be less than 1000!');
        }
    }
}

最佳实践:批量处理数据

由于 Trigger 类是在数据被操作的时候自动执行,而 Salesforce 是运行在云端的平台,所以对于 Trigger 类的一个最佳实践是:尽量批量处理数据,而非对每条数据在 Trigger 中单独处理。

比如在普通的 Apex 类中,有一段代码要更新一组 Contact 数据:

update contactList;
而系统中需要一个 Trigger 类在每个 Contact 对象更新之前设定其 FirstName 的值。

如果在 Trigger 中每次只处理一条数据,比如:

trigger ContactRenameTrigger on Contact (before update) {
    Contact c = Trigger.New[0];
    c.FirstName = 'default first name';
}


那么在一组 Contact 数据要更新的情况下,该 Trigger 会被执行很多次,每条数据一次。

如果将 Trigger 改为处理所有数据,比如:

trigger ContactRenameTrigger on Contact (before update) {
    for(Contact c : Trigger.New) {
        c.FirstName = 'default first name';
    }
}



那么 Trigger 只需要执行一次,就可以将要处理的一组 Contact 数据中每条数据都进行更新,提高了效率。

在 Trigger 中也可以执行 SOQL 查询和 DML 操作。这时也要尽量先准备好一组数据,然后执行一次 DML 操作,而非对每一条记录单独执行一次。

比如,在更新每个 Account 数据之后,都要插入一条 Opportunity 数据,那么可以在 Trigger 中先用 SOQL 查询提取出所有的 Account 数据,然后对于每一个 Account 数据新建一个 Opportunity 数据,再一次性将所有的 Opportunity 数据用 DML 语句插入数据库中。

trigger AddOpportunityTrigger on Account (after update) {
    List<Opportunity> oppList = new List<Opportunity>();

    List<Account> accList = [SELECT Id, Name FROM Account WHERE Id IN :Trigger.New];

    for(Account a : accList) {
        oppList.add(new Opportunity(Name=a.Name+' opp', 
                                    StageName='Prospecting',
                                    CloseDate=System.today().addMonths(1),
                                    AccountId=a.Id)
                                    );
    }

    if(oppList.size() > 0) {
        insert oppList;
    }
}