Monday, May 1, 2023

Mixed DML Operation Error in Salesforce

A mixed DML Operation Error in Salesforce 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(User), can’t be mixed with DML on other sObjects(Standard/Custom Objects) in the same transaction.

How do you resolve a mixed DML exception?

  • To avoid this error, we should perform DML operation on standard/custom object records in a different transaction.
  • In general all the apex classes and apex triggers execute synchronously (execute immediately).
  • If we perform DML operation on standard/custom object records asynchronously (execute in future context), we can avoid MIXED-DML-OPERATION error.
  • To execute logic asynchronously keep the logic in an apex method (in a separate apex class, not in same apex trigger) which is decorated with @future annotation.

In the below example, Account and User records are inserted in the
same transaction.
This is will throw the Mixed DML Exception.

public class MixedDMLError {
  public static void myMethod() {
      Account a = new Account(Name='XploreSFDC');
      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 = 'XploreSFDC'
          email='XploreSFDC@XploreSFDC.com'
          emailencodingkey='UTF-8', lastname='Max'
          languagelocalekey='en_US'
          localesidkey='en_US', profileid = p.Id
userroleid = r.Id,
          timezonesidkey='America/Los_Angeles'
          username='XploreSFDC@XploreSFDC.com');
      insert usr;
  }
}

Let us see how we can fix it

public class MixedDMLErrorFixed {
  public static void myMethod() {
      Account a = new Account(Name='XploreSFDC');
      insert a;
      FutureDemo.insertUser();
  }
}

public class FutureDemo {
  @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 = 'XploreSFDC'
          email='XploreSFDC@XploreSFDC.com'
          emailencodingkey='UTF-8', lastname='Max'
          languagelocalekey='en_US'
          localesidkey='en_US', profileid = p.Id
userroleid = r.Id,
          timezonesidkey='America/Los_Angeles'
          username='XploreSFDC@XploreSFDC.com');
      insert usr;
  }
}

Few Point to keep in mind:

  • Future method execute asynchronously (whenever server is free it will execute in future context).
  • We should not declare @future method in Apex Trigger.
  • @future method should be always static.
  • @future method accepts only primitive data types (Integer, String, Boolean, Date, etc…) as parameters and it won’t accept non-primitive data types (sObject,Custom Objects and standard Objects etc.. ) as parameters.
  • @future method should not contain return type. 
  • From an apex trigger we can make only make asynchronous call outs. To make call out we should include “callout = true” beside the future @annotation.
  • We cannot perform synchronous call outs from Apex Trigger.

No comments:

Post a Comment