Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid MIXED_DML_OPERATION error in Salesforce tests that create Users

Sometimes in Salesforce tests you need to create User objects to run part of the test as a speciifc type of user.

However since the Salesforce Summer 08 update, attempts to create both User objects and normal objects (such as Accounts) in the same test lead to the following error:

MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): User, original object: Account

Note that the error doesn't happen when you run the tests from Eclipse/Force.com IDE, but it does happen when you deploy to Salesforce and then run the tests from within Salesforce.

How do I re-write my tests to avoid this error?

Here's a simple example of a test that causes the error:

static testMethod void test_mixed_dmlbug() {             Profile p = [select id from profile where name='(some profile)'];     UserRole r = [Select id from userrole where name='(some role)'];     User u = new User(alias = 'standt', email='[email protected]',              emailencodingkey='UTF-8', lastname='Testing',              languagelocalekey='en_US',              localesidkey='en_US', profileid = p.Id, userroleid = r.Id,             timezonesidkey='America/Los_Angeles',              username='[email protected]');     Account a = new Account(Firstname='Terry', Lastname='Testperson');     insert a;      System.runAs(u) {         a.PersonEmail = '[email protected]';         update a;     }  } 
like image 935
codeulike Avatar asked Mar 05 '10 14:03

codeulike


People also ask

How do I get rid of the mixed DML error in Salesforce?

Use @future to Bypass the Mixed DML Error in a Test Method 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.

Which of the following option would you use to overcome Mixed_dml errors?

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.

How can you avoid mixing DML and test class?

Using Test. startTest and Test. stopTest to bypass the mixed DML error in a Test Method. The mixed DML exception error is still sometimes returned even if you enclose the code block that performs the mixed DML operations within a System.

What is mixed DML statement error?

A Mixed DML operation error occurs when you try to persist in the same transaction, changes to a Setup Object and a non-Setup Object. For example, if you try to update an Opportunity record and a User record at the same time.


2 Answers

Not many Salesforce people on here yet, I guess.

I found a solution, I don't know why it works, but it works.

All parts of the test that access normal objects need to be wrapped in a System.runAs that explicitly uses the current user, like this:

User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ]; System.runAs ( thisUser ) {     // put test setup code in here } 

So, the example text_mixed_dmlbug method given in the question, would become:

static testMethod void test_mixed_dmlbug() {       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='[email protected]',              emailencodingkey='UTF-8', lastname='Testing',              languagelocalekey='en_US',              localesidkey='en_US', profileid = p.Id, userroleid = r.Id,             timezonesidkey='America/Los_Angeles',              username='[email protected]');         a = new Account(Firstname='Terry', Lastname='Testperson');         insert a;     }     System.runAs(u) {         a.PersonEmail = '[email protected]';         update a;     }  } 

Then the MIXED_DML_OPERATION errors stop happening.

like image 197
codeulike Avatar answered Sep 28 '22 07:09

codeulike


It seems like you've found a workaround. I just wanted to try and clear up why you where getting this error.

I think you are running into this issue (per http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dml_non_mix_sobjects.htm):

sObjects That Cannot Be Used Together in DML Operations

Some sObjects require that you perform DML operations on only one type per transaction. For example, you cannot insert an account, then insert a user or a group member in a single transaction. The following sObjects cannot be used together in a transaction:

* Group1 * GroupMember * QueueSObject * User2 * UserRole * UserTerritory * Territory 

Important The primary exception to this is when you are using the runAs method in a test.

In addition, the Summer 08 Release notes (that link is a PDF) say:

In previous releases, in a single transaction that involved triggers, you could perform DML operations on more than one type of sObject, for example, you could insert an account, then insert a user. As of Summer '08, you can only perform DML operations on a single type of sObject from the following list of sObjects.

For example, you cannot insert an account, then insert a user, or update a group, then insert a group member.

  • Group
  • GroupMember
  • QueueSObject
  • User
  • UserRole
  • UserTerritory
  • Territory

In addition, User and Territory now support the insert and update DML operations, and UserRole now supports the insert, update delete and upsert DML operations.

Apex DML operations are not supported on the following sObjects:

  • AccountTerritoryAssignmentRule
  • AccountTerritoryAssignmentRuleItem
  • UserAccountTeamMember
like image 31
Paddyslacker Avatar answered Sep 28 '22 06:09

Paddyslacker