I have a Contact trigger that, after update, checks to see if some fields (Email or Team) were changed, and if they were, it updates the fields on the Contact's associated User record. These two different updates are nearly identical in implementation, and it is impossible for a single record to ever meet both conditions, so a record is only being added to ONE of TWO final lists for update.
If I update the Contacts team and save the record, the users team is updated without an issue, but if I update the Contacts email it fails with a MIXED_DML_OPERATION saying I can't update User after updating Contact. There are no triggers running on the User object that update the contact after the User record is updated.
System.DmlException: Update failed. First exception on row 0 with id 0051h000001YZ59AAG; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): User, original object: Contact: []
Question: Why is one of these transactions being treated differently than the other? Both are triggered by an update to the Contact record, both find Contacts that meet appropriate conditions and put them in a list, a Contact can never be in both lists in the same transaction, and one of the User updates works fine while the other does not.
Code:
ContactTriggerHandler.cls:
if (CONDITION1) {
if (!isCommunityUser) {
contactsForCommunity.add(c);
} else {
if (teamChanged) {
teamChanges.add(c);
}
}
} else {
if(!isCommunityUser){
if (String.isBlank(relatedContact) && !String.isBlank(conEmail)) {
contactsForCommunity.add(c);
}
}else{
if(emailChanged && !emailInUse){
updateUsernameContacts.add(c);
}
}
}
if(!updateUsernameContacts.isEmpty()){
UserUtil.updateUsernames(updateUsernameContacts);
}
if(!teamChanges.isEmpty()){
UserUtil.updateLearningTracks(teamChanges);
}
UserUtil.updateLearningTracks (Works):
public static void updateLearningTracks(List<Contact> contacts){
System.debug('Start UserUtil.updateLearningTracks');
String userLearningTrack,contactLearningTrack;
Boolean isChanged;
List<User> toUpdate = new List<User>();
List<User> users = [SELECT Id,Username,
Email,ContactId,
Contact.Team_Assignment__c
FROM User
WHERE ContactId IN : contacts];
for(User u : users){
contactLearningTrack = u.Contact.Team_Assignment__c;
userLearningTrack = u.Team_Assignment__c;
isChanged = contactLearningTrack != userLearningTrack;
if(isChanged){
toUpdate.add(u);
}
}
if(!toUpdate.isEmpty()){
update toUpdate;
}
System.debug('End UserUtil.updateLearningTracks');
}
UserUtil.updateUsernames (DOES NOT WORK - MIXED DML) :
public static void updateUsernames(List<Contact> contacts){
String username;
String conEmail;
Boolean isChanged;
List<User> toUpdate = new List<User>();
List<User> users = [SELECT Id,Username,
Email,ContactId,
Contact.Email
FROM User
WHERE ContactId IN : contacts];
for(User u : users){
username = u.Username;
conEmail = u.Contact.Email;
isChanged = username != conEmail;
if(isChanged){
u.Username = conEmail;
u.Email = conEmail;
toUpdate.add(u);
}
}
if(!toUpdate.isEmpty()){
update toUpdate;
}
}