如何避免在创建用户的Salesforce测试中出现MIXED_DML_OPERATION错误

cod*_*ike 32 unit-testing salesforce apex-code

有时在Salesforce测试中,您需要创建User对象以作为特定类型的用户运行部分测试.

但是,自Salesforce Summer 08更新以来,尝试在同一测试中创建User对象和普通对象(如Accounts)会导致以下错误:

MIXED_DML_OPERATION,更新非安装对象后,不允许对安装对象进行DML操作(反之亦然):用户,原始对象:帐户

请注意,从Eclipse/Force.com IDE运行测试时不会发生错误,但是当您部署到Salesforce然后从Salesforce中运行测试时,确实会发生错误.

如何重新编写测试以避免此错误?

以下是导致错误的测试的简单示例:

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='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');
    Account a = new Account(Firstname='Terry', Lastname='Testperson');
    insert a;

    System.runAs(u) {
        a.PersonEmail = 'test@madeupaddress.com';
        update a;
    }

}
Run Code Online (Sandbox Code Playgroud)

cod*_*ike 40

我猜这里的Salesforce人员不多.

我找到了一个解决方案,我不知道它为什么有效,但它确实有效.

访问普通对象的测试的所有部分都需要包装在显式使用当前用户的System.runAs中,如下所示:

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

因此,问题中给出的示例text_mixed_dmlbug方法将变为:

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='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='Terry', Lastname='Testperson');
        insert a;
    }
    System.runAs(u) {
        a.PersonEmail = 'test@madeupaddress.com';
        update a;
    }

}
Run Code Online (Sandbox Code Playgroud)

然后MIXED_DML_OPERATION错误停止发生.

  • 六年后,我再次遇到这个问题并用谷歌搜索到这里,发现我以前做过这一切.那有徽章吗? (5认同)
  • 因为runAs块的内容将获得自己的上下文,至少为了MIXED_DML_EXCEPTION.我不知道为什么,但你可以将它包装在System.RunAs(新用户(id = UserInfo.getUserId()){blah}来解决这个问题. (3认同)

Pad*_*ker 13

好像你找到了一个解决方法.我只是想尝试清理为什么你在哪里得到这个错误.

我认为你遇到了这个问题(根据http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dml_non_mix_sobjects.htm):

在DML操作中无法一起使用的sObjects

某些sObject要求您对每个事务仅对一种类型执行DML操作.例如,您无法插入帐户,然后在单个事务中插入用户或组成员.以下sObjects不能在事务中一起使用:

* Group1
* GroupMember
* QueueSObject
* User2
* UserRole
* UserTerritory
* Territory
Run Code Online (Sandbox Code Playgroud)

重要说明这一点的主要例外是在测试中使用runAs方法时.

此外,Summer 08发行说明(该链接是PDF)说:

在以前的版本中,在涉及触发器的单个事务中,您可以对多种类型的sObject执行DML操作,例如,您可以插入帐户,然后插入用户.从Summer '08开始,您只能从以下sObject列表中对单一类型的sObject执行DML操作.

例如,您无法插入帐户,然后插入用户或更新组,然后插入组成员.

  • GroupMember
  • QueueSObject
  • 用户
  • UserRole的
  • UserTerritory
  • 领土

此外,User和Territory现在支持插入和更新DML操作,UserRole现在支持插入,更新删除和upsert DML操作.

以下sObjects不支持Apex DML操作:

  • AccountTerritoryAssignmentRule
  • AccountTerritoryAssignmentRuleItem
  • UserAccountTeamMember


小智 7

salesforce文档中实际记录了此行为:http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_dml_non_mix_sobjects.htm?SearchType .阅读它所说的"重要"这个的主要例外是当你在测试中使用runAs方法时