I have a trigger on a Contact object and when I try to update a User record in this trigger I get the following exception:
"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"
Trigger code:
trigger UpdateContactTrigger on Contact (after update) {
User u = [SELECT Id, IsActive FROM User WHERE IsActive = true];
u.IsActive = false;
update u;
}
How can I avoid this error while updating User record's fields from a Contact trigger?
Salesforce categorizes objects into so called setup and non-setup objects. User is a setup object while Contact is a non-setup object. Salesforce restricts DML operations so that both kinds of objects can't be manipulated in the same context.
There's a workaround for this problem placing DML code for conflicting object to a @future method as described in the end of this document and the previous answer.
In my case using @future method didn't work because there was an update trigger on User that called another @future method and Salesforce doesn't allow calling a @future method from another @future method.
So I came up with another workaround that works for some cases for User objects.
From API version 15.0 Salesforce actually allows updates on custom fields of a User object in the same context with non-setup object updates. So if you need to update User's standard field, you can use a custom proxy field with a 'before update' trigger on the User object.
If you need to change User's IsActive field, add a custom IsActiveProxy field to the user and perform your update in a trigger on it:
trigger UpdateContactTrigger on Contact (after update) {
User u = [SELECT Id, IsActive FROM User WHERE IsActive = true];
u.IsActiveProxy__c = false;
update u;
}
Then create a 'before update' trigger on a User that copies the proxy field value to the standard field:
trigger BeforeUpdateUserTrigger on User (before update) {
for(User user : trigger.new) {
if(user.IsActive != user.IsActiveProxy__c) {
user.IsActive = user.IsActiveProxy__c;
}
}
}
That's it! It worked for me.