
Inline adoc files when they are included exactly once. Also fix language tags because this inlining gives us better information on what language the code is written in.
124 lines
3.5 KiB
Plaintext
124 lines
3.5 KiB
Plaintext
== Why is this an issue?
|
|
|
|
In order to protect shared resources, Salesforce enforces a maximum number of DML statements which can be executed inside a single https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_transaction.htm[transaction]. This is part of https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm[Governor limits]. If a DML statement is nested inside a loop's body (For/While/Do-While) it might be executed more times than the Governor limit allows, making the code fail.
|
|
|
|
|
|
Thus it is a best practice to not have DML statements nested in the body of loops and instead perform the DML operation on a list of sObjects.
|
|
|
|
|
|
This rule raises an issue when it detects DML statements inside a loop.
|
|
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,apex]
|
|
----
|
|
public class myDMLLoop {
|
|
public static void myFunction() {
|
|
for (Task task: [Select Id, subject from Task]) {
|
|
if (task.subject == 'foo') {
|
|
task.subject = 'bar';
|
|
update task; // Noncompliant
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Query in a while loop
|
|
public class myDMLLoop {
|
|
public static void myFunction(Task[] tasks) {
|
|
Integer i = 0;
|
|
while ( i < 1000) {
|
|
Task task = tasks[i];
|
|
if (task.subject == 'foo') {
|
|
task.subject = 'bar';
|
|
update task; // Noncompliant
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Query in a do-while loop
|
|
public class myDMLLoop {
|
|
public static void myFunction(Task[] tasks) {
|
|
Integer i = 0;
|
|
do {
|
|
Task task = tasks[i];
|
|
if (task.subject == 'foo') {
|
|
task.subject = 'bar';
|
|
update task; // Noncompliant
|
|
}
|
|
i++;
|
|
} while (i < 1000);
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
=== Compliant solution
|
|
|
|
[source,apex]
|
|
----
|
|
public class myDMLLoop {
|
|
public static void myFunction() {
|
|
List<Task> updatedTasks = new List<Task>();
|
|
for (Task task: [Select Id, subject from Task]) {
|
|
if (task.subject == 'foo') {
|
|
task.subject = 'bar';
|
|
updatedTasks.add(task);
|
|
}
|
|
}
|
|
update updatedTasks;
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== Resources
|
|
|
|
* https://developer.salesforce.com/index.php?title=Apex_Code_Best_Practices&oldid=26951[Apex Code Best Practices]
|
|
* https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_loops_for_SOQL.htm[SOQL For Loops]
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Move this DML statement out of the loop or process sObjects by batch.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 5 Jul 2019, 17:35:38 Nicolas Harraudeau wrote:
|
|
If the rule raise false positives one possible exception is:
|
|
|
|
|
|
=== Exceptions
|
|
|
|
No issue will be raised when the DML statement is executed on a collection returned by a for loop. In this case the for loop already executed the DML statement in bulk.
|
|
|
|
|
|
----
|
|
public class myDMLLoop {
|
|
public static void myFunction() {
|
|
for (Task[] task: [Select Id, subject from Task]) { // Ok. The SOQL query is processing a batch of Tasks instead of a single one
|
|
task.subject = task.subject + ' processed';
|
|
update task; // This update a batch of Tasks
|
|
}
|
|
for (List<Task> tasks: [Select Id, subject from Task]) { // Same here
|
|
for (Task task: tasks) {
|
|
task.subject = task.subject + ' processed';
|
|
}
|
|
update tasks;
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
endif::env-github,rspecator-view[]
|