4

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?

2 Answers 2

10

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.

Sign up to request clarification or add additional context in comments.

Comments

2

You should define @future method which will do the update and call this method from trigger.

@future
updateUser(){
    User u = [SELECT Id, IsActive FROM User WHERE IsActive = true];

    u.IsActive = false;
    update u;
}

and call it in trigger:

trigger UpdateContactTrigger on Contact (after update) {
    updateUser();
}    

1 Comment

Yes I have tried this approach but it doesn't work for me because there's a trigger on the User that calls a '@future' method and calling '@future' method from another '@future' method is not allowed in Salesforce. I have found an alternative workaround that solves the problem and I will post it as an answer later. Thanks for reply!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.