I hope you got the got Mixed DML Operation Error in Salesforce while working with a Test class, or doing some automation on a user object. Let’s see how to fix the Mixed DML Operation Error in Salesforce and avoid the MIXED-DML-OPERATION error.
What is a Mixed DML Operation Error?
A mixed DML Operation Error comes when you try to perform DML operations on setup and non-setup objects in a single transaction. DML operations on certain sObjects, sometimes referred to as setup objects, can’t be mixed with DML on other sObjects in the same transaction.
This restriction exists because some sObjects affect the user’s record access in the org. You must insert or update these types of sObjects in a different transaction to prevent operations from happening with incorrect access-level permissions.
For example, you can’t update an account and a user role in a single transaction.
What is Setup Object?
Setup objects are the sObjects that affect the user’s access to records in the organization. Here are examples of the Setup Objects:
- ObjectPermissions
- PermissionSet
- PermissionSetAssignment
- QueueSObject
- Territory
- UserTerritory
- UserRole
- User
How to Fix MIXED DML Operation Error
We should perform DML operation on standard/custom object records in a different transaction. Let’s see how to avoid the MIXED DML Operation error:
- Use Future methods helps in avoiding mixed DML errors
- Mixed DML Operations in Test Methods
- Mixed DML Operations in System.runAs Blocks
- Use @future to Bypass the Mixed DML Error in a Test Method
Avoiding mixed DML errors using @Future method
We can use Future methods to avoid mixed DML errors in Salesforce. Let’s see when mixed Dml issues come in salesforce. In below code we are trying to insert the Account and user roles togather.
public class MixedDMLErrorDemo {
public static void myMethod() {
Account a = new Account(Name='ApexHours');
insert a;
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='CEO'];
User usr = new User(alias = 'apexs', email='[email protected]',
emailencodingkey='UTF-8', lastname='Hours',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='[email protected]');
insert usr;
}
}
When you will to execute the above code you will get “System.DmlException: Insert failed. First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa):
” error.
Let’s see how to perform mixed DML operations by using a future method to perform a DML operation on the User object. We can simply move the Setup object transection into a future context to avoid it. Like the below code.
public class MixedDMLErrorDemo {
public static void myMethod() {
Account a = new Account(Name='ApexHours');
insert a;
UtilFutureDemo.insertUser();
}
}
Use Future methods helps in avoiding mixed DML errors like below code.
public class UtilFutureDemo {
@future
public static void insertUser() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='CEO'];
User usr = new User(alias = 'apexs', email='[email protected]',
emailencodingkey='UTF-8', lastname='Hours',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='[email protected]');
insert usr;
}
}
How do you resolve mixed DML exceptions in Test class?
We can use System.runAs
Blocks in Salesforce to avoid Mixed DML Operations errors.
@isTest
private class MixedDMLTestClassDemo {
static testMethod void mixedDMLExample() {
User u;
Account a = new Account(Name='ApexHours');
insert a;
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
System.runAs (thisUser) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='CEO'];
User usr = new User(alias = 'apexs', email='[email protected]',
emailencodingkey='UTF-8', lastname='Hours',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='[email protected]');
insert usr;
}
}
}
Use @future to Bypass the Mixed DML Error in a Test Method
You can also use the future method in the test class. Check out the example here.
Even if you put Create Account and Create User transaction, both in a single System.runAs block. It will work.