経営陣は、年間売上高が100万ドルを超える取引先に対して商談を自動的に作成するよう依頼しました。開発者は、この要件を満たすために、取引先オブジェクトに次のトリガを作成しました。 for (Account a : Trigger.new) { if (a.AnnualRevenue > 1000000) { List<Opportunity> oppList = [SELECT Id FROM Opportunity WHERE AccountId = :a.Id]; if (oppList.size() == 0) { Opportunity oppty = new Opportunity(Name = a.Name, StageName = 'Prospecting', CloseDate = System. today().addDays(30)); insert oppty; } } } ユーザーはUIから取引先レコードを更新でき、年間売上高の高い取引先向けに作成された商談を確認できます。しかし、管理者がデータローダーを使用して179件の取引先リストをアップロードしようとすると、システム例外エラーが発生し、アップロードに失敗します。 上記のコード セグメントを修正するために開発者が実行する必要がある 2 つのアクションはどれですか。 2つの答えを選択してください
正解:A,C
This is a classicbulkification problem, covered under"Apex Development Best Practices"in the PD1 guide. Reference:Apex Developer Guide - Bulk Design Patterns D (Correct):DML operations (like insert) in a loop can cause theDML 151 limiterror. Moving them outside the loop and collecting records in a list before performing a single DML operation is best practice.Reference: Salesforce Platform Developer I Study Guide - Process Automation and Logic (30%)
最新のコメント (最新のコメントはトップにあります。)
正解は **A** と **C** です。
この問題は、Salesforce開発における最も基本的なルールである **「Bulk化(一括処理化)」** が行われていないことによる **ガバナ制限(Governor Limits)違反** が原因です。
### 原因の解説
Salesforceのトリガーは、データローダーなどで大量のレコードが一括更新される際、最大200レコードずつのバッチ(塊)として処理されます。
このコードは `for` ループの中にデータベース操作(SOQLとDML)を含んでいるため、179件のレコードを処理しようとすると以下の制限を超えてしまいます。
1. **SOQLクエリの制限 (最大100回)**
* ループ内で `[SELECT Id FROM Opportunity ...]` を実行しています。
* 101件目のレコードを処理した時点で、「Too many SOQL queries: 101」エラーが発生します。
2. **DMLステートメントの制限 (最大150回)**
* ループ内で `insert oppty;` を実行しています。
* 条件を満たすレコードが151件以上ある場合、「Too many DML statements: 151」エラーが発生します。
### 正解の解説
**A. for ループの外側にある既存の商談をクエリします。**
* **対策:** ループの中で1回ずつ検索するのではなく、対象となる取引先IDをSetやListに集め、ループの外で **1回のSOQLクエリ** を発行して、既存の商談を一括取得します(Mapなどに格納して比較します)。これでクエリ回数は1回で済みます。
**C. 機会を保存する DML を for ループの外側に移動します。**
* **対策:** 作成する商談を `List<Opportunity>` に追加していき、ループが終わった後に **`insert oppList;`** のようにリストに対して1回だけDMLを実行します。これでDML回数は1回で済みます。
-----
### 修正後のコードイメージ
```apex
// 1. 対象の取引先IDを収集
Set<Id> accIds = new Set<Id>();
for (Account a : Trigger.new) {
if (a.AnnualRevenue > 1000000) {
accIds.add(a.Id);
}
}
// 2. ループの外で一括クエリ (SOQLのBulk化) - 選択肢A
List<Opportunity> existingOpps = [SELECT AccountId FROM Opportunity WHERE AccountId IN :accIds];
Set<Id> accIdsWithOpp = new Set<Id>();
for(Opportunity opp : existingOpps) {
accIdsWithOpp.add(opp.AccountId);
}
// 3. 商談作成用のリストを準備
List<Opportunity> oppsToInsert = new List<Opportun...