function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
cjencjen 

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

Hi, i want to create a contact when a new user is created. I tried process builder and trigger but get the following error (trigger):

MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa):Contact, original object: User: []: Trigger.NewContactOnUser: line 19, column 1

Here is the code:

trigger NewContactOnUser on User (before insert) {
    List<Contact> contacts = new List<Contact>();
    for (User u: trigger.new){
        Contact c = new Contact();
        c.FirstName = u.FirstName;
        c.LastName = u.LastName;
        c.Email = u.Email;
        c.MailingStreet = u.Street;
        c.MailingCity = u.City;
        c.MailingState = u.State;
        c.MailingCountry = u.Country;
        c.MailingPostalCode = u.PostalCode;
        c.Title = u.Title;
        c.Phone = u.Phone;
        c.AccountID = '001W000000JgPzp';       
        
        contacts.add(c);       
    }
    insert contacts;


Can anyone help fix this or any ideas to create a contact from a user record?

Thanks!
 
Best Answer chosen by cjen
Jithin Krishnan 2Jithin Krishnan 2
Yes. You can change the trigger like this:
trigger NewContactOnUser on User (after insert) {
    List<Contact> contacts = new List<Contact>();
    ID accid='001W000000JgPzp';
    for (User u: trigger.new){
        if(u.Profile.UserLicense.Name=='Salesforce'){
        	MyFutureClass.createContact(u.FirstName, u.LastName, u.Email, u.Street, u.City, 
                                    u.State, u.Country, u.PostalCode, u.Title, u.Phone, accid);
        }
    }
}

Thanks

All Answers

Jithin Krishnan 2Jithin Krishnan 2
Hi,
User is a setup object . DML over setup and non-setup objects cannot be done in same thread or context. For this @future annoation is used to create a contact with the user details. The above problem can be solved by creating a class with a method to create the contact using user details (A future method cannot have SObject parameters, hence the long parameter list) and modifying the trigger as below.

Trigger:
trigger NewContactOnUser on User (after insert) {
    List<Contact> contacts = new List<Contact>();
    ID accid='001W000000JgPzp';
    for (User u: trigger.new){
        MyFutureClass.createContact(u.FirstName, u.LastName, u.Email, u.Street, u.City, 
                                    u.State, u.Country, u.PostalCode, u.Title, u.Phone, accid);
    }
}

Future method:
public class MyFutureClass {
@future
  public static void createContact(String FirstName, String LastName, String Email, String Street,
        						String City, String State, String Country, String PostalCode, String Title,
        						String Phone, ID AccountID){
        Contact c = new Contact();
        c.FirstName = FirstName;
        c.LastName = LastName;
        c.Email = Email;
        c.MailingStreet = Street;
        c.MailingCity = City;
        c.MailingState = State;
        c.MailingCountry = Country;
        c.MailingPostalCode = PostalCode;
        c.Title = Title;
        c.Phone = Phone;
        c.AccountID = AccountID;       
        
     insert c;
  }

}

Please let me know if you need any help.
Thanks.
 
cjencjen
you are a genius! thanks very much!
Jithin Krishnan 2Jithin Krishnan 2
Glad it worked :)
cjencjen
Jithin,  it is possible to put a condition on it, like Where the user license = Salesforce? i only want this to fire when a new Salesforce license user is created, we also have community users, but don't need a contact created when we add them, of course. Thanks, again!!!!!
Jithin Krishnan 2Jithin Krishnan 2
Yes. You can change the trigger like this:
trigger NewContactOnUser on User (after insert) {
    List<Contact> contacts = new List<Contact>();
    ID accid='001W000000JgPzp';
    for (User u: trigger.new){
        if(u.Profile.UserLicense.Name=='Salesforce'){
        	MyFutureClass.createContact(u.FirstName, u.LastName, u.Email, u.Street, u.City, 
                                    u.State, u.Country, u.PostalCode, u.Title, u.Phone, accid);
        }
    }
}

Thanks
This was selected as the best answer
cjencjen
hi jithin, that seemed to work, thanks again. Well, if not obvious im a newbie, but i did try to write a test method. Im' just not getting it, the trigger and class both say 0% coverage. Would you mind taking a look and see where im am messing it up, please? Thanks again, i really appreciate it.

@isTest
private class MyFutureClassTEST {
    static testMethod void validateMyFutureClass() {
    
        Contact c = new Contact();       
       
        c.FirstName = 'FName';
        c.LastName = 'LName';
        c.Email = 'fname@fname.com';
        c.MailingStreet = '1234 Some Street';
        c.MailingCity = 'Somewhere';
        c.MailingState = 'TX';
        c.MailingCountry = 'USA';
        c.MailingPostalCode = '90210';
        c.Title = 'CEO';
        c.Phone = '817-555-4564';
        c.AccountID = '001W000000JgPzp';       
      //Insert Contact        
       insert c;
       
       //Retrieve the new Contact
        c = [SELECT FirstName, LastName, Email, MailingStreet, MailingCity, MailingState, MailingCountry, MailingPostalCode, Title, Phone, AccountID from Contact WHERE Id =:c.Id];
      
      
       //Test correctly created the contact
       
       System.AssertEquals('FName', c.FirstName);
       System.AssertEquals('LName',c.LastName);
       System.AssertEquals('fname@fname.com',c.Email);
       System.AssertEquals('1234 Some Street',c.MailingStreet);
       System.AssertEquals('Somewhere',c.MailingCity);
       System.AssertEquals('TX',c.MailingState);
       System.AssertEquals('USA',c.MailingCountry);
       System.AssertEquals('90210',c.MailingPostalCode);
       System.AssertEquals('CEO',c.Title);
       System.AssertEquals('817-555-4564',c.Phone);
       System.AssertEquals('001W000000JgPzp',c.AccountID); 
       

    
    }
    
}
Jithin Krishnan 2Jithin Krishnan 2
In the above test method, you are creating a contact object. So the trigger on user object won't be fired. Your test class should begin by creating a user object and inserting it. When inserting the user object, the trigger will be fired leading to the creation of a corresponding contact record. You can then use an SOQL to get the contact giving the user details as the condition and cross check the expected results with System.AssertEquals method. 
Note: Put the 'insert userObject;' statement inside test.startTest() and test.stopTest() as the contact is created using a future method.
Thanks.
Jithin Krishnan 2Jithin Krishnan 2
Hi cjen,
As a best practice, please mark the answer if it helped you.
Thanks.