[SalesForce] Trigger to create a Contact after User is created (w/ error)

Getting an error with trigger/class.

We have an automated process the creates a user record (from our AD/SSO process). When a User is created, a trigger sends an email to our support group to finalize some manual setup steps, but one of those manual steps is to create a Contact record and relate the User to it. I'm trying to add to our trigger to also create and relate the contact record. However, when it fires, I get the following error.

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger NewUserCreatedTrigger caused an unexpected exception, contact your administrator: NewUserCreatedTrigger: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: 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: []: Class.NewUserCreatedNotification.createUserContact: line 32, column 1

Here's the TRIGGER:

trigger NewUserCreatedTrigger on User (after insert) {
    user[] users = trigger.new;

    NewUserCreatedNotification.sendEmail(users);
    NewUserCreatedNotification.createUserContact(users);
}

And here's the CLASS:

public class NewUserCreatedNotification  {
    public static void sendEmail(user[] newUser){
        for (user u : newUser){
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] {'SalesforceSupport@companyname.com'};
            mail.setToAddresses(toAddresses); 
            mail.setSenderDisplayName ('Salesforce Support');
            mail.setSubject('A New Salesforce User has been created in ORG-2'); 
            mail.setPlainTextBody(GetMessageBodyText(u.ID)); 
            Messaging.sendEmail(new Messaging.SingleEMailMessage[]{mail});
        }
    }

    public static void createUserContact(user[] newUser){    
        for (user u: newUser){        
            account myFirm = [Select ID from account where name = 'CorpName'];
            Contact userContact = new Contact(
                user__c = u.ID,
                AccountID = myFirm.id,
                FirstName = u.firstname,
                Lastname = u.lastname,
                Title = u.title,
                Department = u.department,
                Phone = u.Phone,
                email = u.email,
                MailingStreet = u.street,
                MailingCity = u.city,
                MailingState = u.state,
                MailingPostalCode = u.postalcode,
                MailingCountry = u.country);
                insert userContact;

        }
    }

    public static string GetMessageBodyText(Id userID){
        user q = [select id, name, firstname, lastname, ProfileID, email,UserRoleID, userrole.name, profile.name, CreatedDate,LastLoginDate,FederationIdentifier from user where id =: userID];
        return ' A new user record for '+ q.name +', has been created in ORG-2.\n Please confirm that this user has the correct security and Role settings.\n\n Name:  '+
                q.name+'\n Email Address:  '+
                q.Email+'\n Profile:  '+
                q.Profile.Name+'\n Role:  '+
                q.UserRole.Name+'\n Federation ID:  '+
                q.FederationIdentifier+'\n Created Date:  '+
                q.CreatedDate;      
    }
}

The email sends fine if I remove the Contact part, so I know that's not it. Thoughts?

Best Answer

As the MIXED_DML_OPERATION implies, you can't simply create a user (or other "Setup" type objects), and contacts (or other non-"Setup" type objects) in the same transaction. The usual way to avoid this is to make the function asynchronous.

@future public static void createUserContact(Set<Id> newUserIds){

Note that you can only send "primitives" through a future method, so you'll have to change your trigger slightly:

NewUserCreatedNotification.createUserContact(Trigger.newMap.keySet());

Also, your function doesn't support mass imports of users, so you might want to fix that.

Related Topic