[salesforce]SOQLでガバナ制限を超える方法1 – SOQL query for loop
Force.com上で開発を進めていると、いつか必ずぶつかるのがガバナ制限との戦い。そんなガバナ制限の1つであるSOQLに関する制限を超える方法の1つである「SOQL query for loop」について解説します。
SOQLで取得できるレコード数に関するガバナ制限
SQOL処理を使うことで、特定のオブジェクト内のレコードを検索してその結果レコードリストを得ることができます。しかしこの結果リストとして一度のSOQL文で得ることが出来るレコード数には厳しい制限があり、「トリガ内からは1000レコード」「Testコードからは500レコード」「その他からは10000レコード」となっています。
これくらいのレコード数は簡単に超えてしまいそうなもので、例えば以下のようなSOQLを実行してaccountオブジェクト全体を検索した場合、
[php]
Account[] accts = [SELECT id FROM account];
[/php]
accountオブジェクトにガバナ制限を超える大量のレコードが保存されていると、ガバナ制限を超えてしまってランタイムエラーになります。
それでもガバナ制限を超えるレコードをSOQLで扱いたい場合はあります。そんな時の回避策の1つに「SOQL query for loop」というものがあります。
SOQL query for loopの書き方
SOQL query for loopとは、forループ文の条件式の部分にSOQL文を書く方法を指します。これには2通りの方法があり、SOQLの結果を単一レコードで受け取るか、複数レコードのリストで受け取るか、を選ぶことが出来ます。
SOQLで取得したレコードセットに対してDML処理をしない場合の例
[php]
for (Account a : [SELECT id, name FROM account
WHERE name LIKE ‘Acme’]) {
//色々コードを書く
}
[/php]
SOQLで取得したレコードセットに対してDML処理をしたい場合の例
[php]
for (List<Account> accts : [SELECT id, name FROM account
WHERE name LIKE ‘Acme’]) {
// 色々コードを書く
update accts;
}
[/php]
後者の場合は、forループの中でacctsという配列の中にSQOLで取得したレコードセットが200レコードずつ格納されます。forループ内でDML処理をする時はその200レコードずつ処理を行うことになります。
例えば実例はこんな感じ。
[php]
public void massUpdate() {
for (List<Contact> contacts:
[Select FirstName, LastName From Contact]) {
for(Contact c : contacts) {
if (c.FirstName == ‘Barbara’ &&
c.LastName == ‘Gordon’) {c.LastName = ‘Wayne’;
}
}
update contacts;
}
}
[/php]
Contactオブジェクトのレコードを検索して、その結果レコードが大量の場合も一括更新できるように書いた例です。3行目のfor文内のSQOLでContactオブジェクトの大量のレコードが取得されてそれが200レコードごとの配列に分割されてcontactsという配列に格納されます。その後4行目のfor文でその200レコードが格納されているレコードセット内の各レコードの各フィールド値を書き換えて、9行目でDML処理を実行してレコードの更新を完了。この処理を繰り返すことで全レコードに対して更新処理が行えることになります。
ただし
このように大量レコードのDML処理を行う場合は、SOQL query for loopを使うのは非推奨となっており、その代わりに最近リリースされた機能であるBatch APEXが推奨されています。これはまた後日。