Skip to main content

Code reviews rule: Data access or manipulation in loops

Written by David Martin
Updated this week

Data access or manipulation in loops

Why is this an issue?

Salesforce enforces strict governor limits on the number of SOQL queries (100) and DML statements (150) allowed per transaction. When a query or DML operation is placed inside a loop, each iteration consumes one of these limited operations. If the loop processes more records than the limit allows, the transaction fails with a System.LimitException.

Beyond governor limits, this pattern is inefficient. Bulkified code that processes records in batches performs significantly better than code that handles records one at a time.

Examples

Example of incorrect code: The following code executes a DML statement for each contact in the list.

public void updateContacts(List<Contact> contacts) {
for (Contact c : contacts) {
c.Description = 'Updated';
update c;
}
}

Example of correct code: The following code collects all modifications and performs a single DML operation.

public void updateContacts(List<Contact> contacts) {
for (Contact c : contacts) {
c.Description = 'Updated';
}
update contacts;
}

Example of incorrect code with a query in a loop:

public void processAccounts(List<Id> accountIds) {
for (Id accId : accountIds) {
Account acc = [SELECT Id, Name FROM Account WHERE Id = :accId];
System.debug(acc.Name);
}
}

Example of correct code with bulkified query:

public void processAccounts(List<Id> accountIds) {
Map<Id, Account> accountMap = new Map<Id, Account>(
[SELECT Id, Name FROM Account WHERE Id IN :accountIds]
);
for (Id accId : accountIds) {
System.debug(accountMap.get(accId).Name);
}
}

How can I fix violations?

This rule supports autofix for basic DML operations in some cases (insert, update, delete).

To manually fix violations:

  1. For DML operations: Collect records in a list during the loop, then perform a single DML operation after the loop completes.

  2. For SOQL queries: Execute the query before the loop using a collection filter (e.g., WHERE Id IN :idList), store results in a Map or List, and access the data during iteration.

When should I disable this rule?

You may dismiss specific violations when the loop is guaranteed to iterate a small, fixed number of times (e.g. iterating over a static configuration list with fewer than 10 items) and bulkification would add unnecessary complexity.

Resources

Did this answer your question?