Apex コードYour Code Our Servers Integer NUM = 10; Account[] accs; // Clean up old data accs = [select id from account where name like 'test%']; delete accs; commit; accs = new Account[NUM]; for (Integer i = 0; i < NUM; i++) { accs[i] = new Account(name='test ' + i, outstandingshares__c=i); } insert accs; Contact[] cons = new Contact[0];
Apex コードとJava の類似点、相違点 類似点 制御構文( if else, for, while ) イテレーション , ジェネリクス( Java5 ) 正規表現クラス 相違点 変数、関数名は大文字小文字を区別しない 文字列はシングルクオート(一重引用符)で括る パッケージ階層はない クラス継承(デフォルトでは有効でない) インラインの SOQL クエリ、 DML 文 global, webService, testMethod などの修飾子
10.
インライン SOQL クエリWeb サービス API の SOQL とほぼ同じ 記述方法 Apex コード中に [ … ] セクションで指定する 結果が 1 件のみの場合は SObject に直接代入可能 Apex コード内の変数を「 : 」を付けることで文中にバインド可能 Account[] accounts = [SELECT Id, Name FROM Account]; Account a = [SELECT Id, Name FROM Account WHERE Id = :accId]; Account[] accs = [SELECT Id, Name FROM Account WHERE Name LIKE :(s + '%')]; Account a = [SELECT Id, Name FROM Account LIMIT 1];
コレクションクラス: Set データの集合を現すデータ構造インターフェースではなくクラス実装( Java とは異なる) 重複を排除 利用例 複数レコードの親レコードを重複なく取得 Set<ID> accountIds = new Set<ID>(); for (Contact c : contacts) accountIds.add(c.AccountId); Account[] accounts = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
トリガ データベース操作に対する各種イベント発生時に起動される Apexコードのロジック データベース・ストアドプロシージャのトリガに類似 トリガ定義の構文 イベント発生のタイミング before insert / before update / before delete after insert / after update / after delete after undelete trigger < トリガ名 > on < オブジェクト名 > ( < イベント > ) { // トリガの処理 }
21.
トリガの記述方法 トリガのコード内から、システム変数 Trigger.new/Trigger.old を用いて新旧レコード情報にアクセスする Trigger.new/Trigger.old からリスト(配列)としてアクセス可能 Trigger.newMap/Trigger.oldMap で ID をキーとするマップ構造としてアクセス可能 trigger testTrigger on Account (after insert) { for (Account a : Trigger.new ) { // 作成された各レコードに対して反復処理する } } trigger oppTrigger on Opportunity (before delete) { for (Quote__c q : [SELECT Opportunity__c FROM Quote__c WHERE Opportunity__c IN :Trigger.oldMap .keySet()]) { Trigger.oldMap .get(q.opportunity__c) .addError('Cannot delete opportunity with a quote'); } }
22.
トリガに対する注意事項 トリガはすべてバルクトリガ(レコードを一括で処理) APIのリクエストなど、作成・更新要求は一度に複数レコードが送信されることが多い トリガから1レコードごとに DB 処理 ? DB 負荷が高い トリガの中から DB にアクセスするときは、 Apex VM ヒープ中でレコード処理してから、まとめてアクセスすること ガバナ制限(実行時のリソース制限) に引っかからないように
SOQL for ループイテレーション処理を SOQL 結果レコードに対して直接適用 通常のリスト配列イテレーションの違い レコードを一時的に格納するためのメモリを必要としない ガバナ制限値を回避して多量のレコードを処理できる for (Account a : [SELECT Id, Name FROM Account WHERE Name LIKE :(s+'%')]) { // 繰り返しコード }
25.
トリガ実装の例 悪い実装例 よい実装例trigger myTrigger on Emp__c (after insert) { Map<Id, Integer> deptEmps = new Map<Id, Integer>(); for (Emp__c emp : Trigger.new) { Integer count = deptEmps.get(emp.Dept__c); if (count==null) count=0; deptEmps.put(emp.Dept__c, count+1); } Dept__c[] depts = [SELECT Id FROM Dept__c WHERE Id IN :deptEmps.keySet()]; for (Dept__c d : depts) { d.EmployeesNumber__c += deptEmps.get(d.Id); } update depts; } trigger myTrigger on Emp__c (after insert) { for (Emp__c emp : Trigger.new) { Dept__c dept = [SELECT Id, Name FROM Account WHERE Id = :emp.Dept__c]; dept.EmployeesNumber__c++; update dept; } } ループ内で DML を発行しているため、 DML 文数のガバナ制限値に抵触する ループ内でクエリを発行しているため、クエリ数のガバナ制限値に抵触する すぐにデータベースに更新するのでなく、一旦値をマップ構造に格納 ループの外側で 一括クエリ&一括 DML 処理