So before knowing how to handle this exception we need to understand why this error comes or say what is the root cause of this error .
Whenever you are getting this error it means that you cannot perform DML on two sObjects (setup & non-setup) in the same transaction. In general, all the apex classes and apex triggers execute synchronously (execute immediately).
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 access to records 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. However, deleting a DML operation has no restrictions.
Resolution for this issue
To execute logic asynchronously keep the logic in an apex method (in a separate apex class, not in same apex trigger) along with @future annotation. This fix will work in the Apex Class/ Apex Trigger, but in case of Test class, we need to use the System.runAs block.
User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
// put test setup code in here
}
Example Test class :
static testMethod void test_mixed_dmlIssue() {
User u;
Account a;
User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
Profile p = [select id from profile where name='(some profile)'];
UserRole r = [Select id from userrole where name='(some role)'];
u = new User(alias = 'standt', email='standarduser@testorg.com',
emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='standarduser@testorg.com');
a = new Account(Firstname='Sfdc', Lastname='Learners');
insert a;
}
System.runAs(u) {
a.PersonEmail = 'mailme@sfdcLearners.com';
update a;
}
}