When you are trying to perform dml operations on setup object and Non-setup object with in a single transaction then you will found an Error.. "MIXED DML EXCEPTION''
To over come mixed DML exception we use the Future method .
Test methods allow for performing mixed Data Manipulation Language (DML) operations that include both setup sObjects and other sObjects if the code that performs the DML operations is enclosed within System.runAs method blocks. You can also perform DML in an asynchronous job that your test method calls. These techniques enable you, for example, to create a user with a role and other sObjects in the same test
There are two way to fix this issue 1) System.runAs 2) @Future
Example: Mixed DML Operations in System.runAs Blocks This example shows how to enclose mixed DML operations within System.runAs blocks to avoid the mixed DML error. TheSystem.runAs block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
@isTest
private class MixedDML {
static testMethod void mixedDMLExample() {
User u;
Account a;
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
// Insert account as current user
System.runAs (thisUser) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
u = new User(alias = 'jsmith', email='jsmith@acme.com',
emailencodingkey='UTF-8', lastname='Smith',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='jsmith@acme.com');
insert u;
a = new Account(name='Acme');
insert a;
}
}
}
Use @future to Bypass the Mixed DML Error in a Test Method Mixed DML operations within a single transaction aren’t allowed. You can’t perform DML on a setup sObject and another sObject in the same transaction. However, you can perform one type of DML as part of an asynchronous job and the others in other asynchronous jobs or in the original transaction. This class contains an @future method to be called by the class in the subsequent example
public class InsertFutureUser {
@future
public static void insertUser() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
User futureUser = new User(firstname = 'Future', lastname = 'User',
alias = 'future', defaultgroupnotificationfrequency = 'N',
digestfrequency = 'N', email = 'test@test.org',
emailencodingkey = 'UTF-8', languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'futureuser@test.org',
userpermissionsmarketinguser = false,
userpermissionsofflineuser = false, userroleid = r.Id);
insert(futureUser);
}
}
The Mixed DML error is generated – when a User performs DML actions on Setup and non-Setup Objects in the same transaction -because some sObjects affect the user's access to records in the org. ... For example, a user cannot update an account, and a user role, in a single transaction.
There are two ways to solve mixed DML error 1. System.runAs 2. @future Example: Mixed DML Operations in System.runAs Blocks This example shows how to enclose mixed DML operations within System.runAs blocks to avoid the mixed DML error. The System.runAs block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
@isTest private class MixedDML { static testMethod void mixedDMLExample() { User u; Account a; User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()]; // Insert account as current user System.runAs (thisUser) { Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']; UserRole r = [SELECT Id FROM UserRole WHERE Name='COO']; u = new User(alias = 'jsmith', email='jsmith@acme.com', emailencodingkey='UTF-8', lastname='Smith', languagelocalekey='en_US', localesidkey='en_US', profileid = p.Id, userroleid = r.Id, timezonesidkey='America/Los_Angeles', username='jsmith@acme.com'); insert u; a = new Account(name='Acme'); insert a; } } }
Use @future to Bypass the Mixed DML Error in a Test Method Mixed DML operations within a single transaction aren’t allowed. You can’t perform DML on a setup sObject and another sObject in the same transaction. However, you can perform one type of DML as part of an asynchronous job and the others in other asynchronous jobs or in the original transaction. This class contains an @future method to be called by the class in the subsequent example.
public class InsertFutureUser { @future public static void insertUser() { Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']; UserRole r = [SELECT Id FROM UserRole WHERE Name='COO']; User futureUser = new User(firstname = 'Future', lastname = 'User', alias = 'future', defaultgroupnotificationfrequency = 'N', digestfrequency = 'N', email = 'test@test.org', emailencodingkey = 'UTF-8', languagelocalekey='en_US', localesidkey='en_US', profileid = p.Id, timezonesidkey = 'America/Los_Angeles', username = 'futureuser@test.org', userpermissionsmarketinguser = false, userpermissionsofflineuser = false, userroleid = r.Id); insert(futureUser); } }
This class calls the method in the previous class.
@isTest public class UserAndContactTest { public testmethod static void testUserAndContact() { InsertFutureUser.insertUser(); Contact currentContact = new Contact( firstName = String.valueOf(System.currentTimeMillis()), lastName = 'Contact'); insert(currentContact); } }
When you are trying to perform dml operations on setup object and Non-setup object with in a single transaction then you will found an Error.. "MIXED DML EXCEPTION''
To over come mixed DML exception we use the Future method .
Please find the below some of the articles and posts on mixed dml:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dml_non_mix_sobjects_test_methods.htm
http://www.infallibletechie.com/2013/01/mixeddmloperation-error-in-salesforce.html
https://developer.salesforce.com/forums/?id=906F00000008wAZIAY
https://developer.salesforce.com/forums/?id=906F0000000941vIAA
https://developer.salesforce.com/forums/?id=906F00000009409IAA
https://developer.salesforce.com/forums/?id=906F0000000921kIAA
https://developer.salesforce.com/forums/?id=906F00000008ypaIAA
http://salesforce.stackexchange.com/questions/13318/error-mixed-dml-operation-on-setup-and-non-setup-objects
http://salesforce.stackexchange.com/questions/66046/mixed-dml-operation-dml-operation-on-setup-object-is-not-permitted-after-you-ha
http://salesforce.stackexchange.com/questions/28314/mixed-dml-operation-error-on-user-trigger-breaking-test-classes
http://stackoverflow.com/questions/10136237/mixed-dml-operation-error-in-salesforce-apex-trigger-when-updating-user-objects
Please do let me know if it helps you.
Regards,
Mahesh
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dml_non_mix_sobjects_test_methods.htm
Test methods allow for performing mixed Data Manipulation Language (DML) operations that include both setup sObjects and other sObjects if the code that performs the DML operations is enclosed within System.runAs method blocks. You can also perform DML in an asynchronous job that your test method calls. These techniques enable you, for example, to create a user with a role and other sObjects in the same test
There are two way to fix this issue
1) System.runAs
2) @Future
Example: Mixed DML Operations in System.runAs Blocks
This example shows how to enclose mixed DML operations within System.runAs blocks to avoid the mixed DML error. TheSystem.runAs block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
Use @future to Bypass the Mixed DML Error in a Test Method
Mixed DML operations within a single transaction aren’t allowed. You can’t perform DML on a setup sObject and another sObject in the same transaction. However, you can perform one type of DML as part of an asynchronous job and the others in other asynchronous jobs or in the original transaction. This class contains an @future method to be called by the class in the subsequent example
Let us know if this will help you
Thanks
AMit Chaudhary
There are two ways to solve mixed DML error
1. System.runAs
2. @future
Example: Mixed DML Operations in System.runAs Blocks
This example shows how to enclose mixed DML operations within System.runAs blocks to avoid the mixed DML error. The System.runAs block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
@isTest
private class MixedDML {
static testMethod void mixedDMLExample() {
User u;
Account a;
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
// Insert account as current user
System.runAs (thisUser) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
u = new User(alias = 'jsmith', email='jsmith@acme.com',
emailencodingkey='UTF-8', lastname='Smith',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='jsmith@acme.com');
insert u;
a = new Account(name='Acme');
insert a;
}
}
}
Use @future to Bypass the Mixed DML Error in a Test Method
Mixed DML operations within a single transaction aren’t allowed. You can’t perform DML on a setup sObject and another sObject in the same transaction. However, you can perform one type of DML as part of an asynchronous job and the others in other asynchronous jobs or in the original transaction. This class contains an @future method to be called by the class in the subsequent example.
public class InsertFutureUser {
@future
public static void insertUser() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
User futureUser = new User(firstname = 'Future', lastname = 'User',
alias = 'future', defaultgroupnotificationfrequency = 'N',
digestfrequency = 'N', email = 'test@test.org',
emailencodingkey = 'UTF-8', languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'futureuser@test.org',
userpermissionsmarketinguser = false,
userpermissionsofflineuser = false, userroleid = r.Id);
insert(futureUser);
}
}
This class calls the method in the previous class.
@isTest
public class UserAndContactTest {
public testmethod static void testUserAndContact() {
InsertFutureUser.insertUser();
Contact currentContact = new Contact(
firstName = String.valueOf(System.currentTimeMillis()),
lastName = 'Contact');
insert(currentContact);
}
}
Thanks in Advance,
JThakkar