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.
Note that you can only send "primitives" through a future method, so you'll have to change your trigger slightly:
Also, your function doesn't support mass imports of users, so you might want to fix that.