1

I need to update user object and termination__c object. Account is lookup to termination__c. I am fetching the contacts related accounts with termination__c record, and fetching the users with that contact id's and making IsActive = false and IsPortalEnabled = false. After these user inactivate the status field in Termination__c object should be set to one value. I am facing problem with updating termination__c object is:

Update failed. First exception on row 0 with id a5t7A00000000Q4QAI; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Termination_Request__c, original object: User:

Here is my code:

public static void disableContacts(List<Termination_Request__c> triggerNew,
    Map<Id, Termination_Request__c> triggerNewMap,
    Map<Id, Termination_Request__c> triggerOldMap) {

    Set<Id> TrIdSet = new Set<Id>();
    Set<Id> AccountIdSet = new Set<Id>();
    list<user> usrList = new list<user>();

    for(Termination_Request__c terr : triggerNew) {
        if(triggerNewMap.get(terr.id).Termination_Date__c !=
            triggerOldMap.get(terr.id).Termination_Date__c  &&
            triggerNewMap.get(terr.id).status__c == 'Partner Deactivated' &&
            triggerOldMap.get(terr.id).Termination_Date__c == null)
        {
            AccountIdSet.add(terr.Account__c);
        }
    }
    if(AccountIdSet !=null && AccountIdSet.size()>0) {
        Map<Id,Contact> conMap = new Map<Id,Contact>([select Id from contact where accountid IN: AccountIdSet]);
        system.debug('===conMap==>'+conMap);
        if(conMap != null && conMap.size()>0) {
            deactivateUsersASyncronus(conMap.keySet());
            /*
            for(Termination_Request__c terr : triggerNew) {
                terr.status__c = 'Termination Complete';
            }
            */
        }
    }
}

@future
public static void  deactivateUsersASyncronus(Set<id> conIds){    

    public static void  deactivateUsers(Set<id> conIds) {

        List<user> updateUserLst = new List<user>();
        Set<ID> terminationAccountSet = new set<ID>();
        List<Termination_Request__c> terminationToupdateList = new List<Termination_Request__c>();

        list<user> usrLst= [SELECT Id, Contactid,username,email,Contact.AccountId,IsPortalEnabled,IsActive FROM User WHERE Contactid IN: conIds AND isActive = true];  
        system.debug('deactivateUsers.usrLst==>'+usrLst);
        for(user u : usrLst) {
            if(u.IsActive || u.IsPortalEnabled) {
                u.IsActive = false;    
                u.IsPortalEnabled = false;
                updateUserLst.add(u);
            }            
            //  if(u.Contact.AccountId !=null) terminationAccountSet.add(u.Contact.AccountId);        
        }
        system.debug('updateUserLst size is==>'+ updateUserLst.size());
        if(!updateUserLst.IsEmpty()) {
            update updateUserLst;
        }
    }
}
//end of future..  

I Just want to know can we update two objects multiple fields update?

  • @Future annot. not working for you? – Ashwani Dec 17 '15 at 11:35
  • yeah. if execute with future method, firing error (future method cannot be called from future method). If i execute without future method the above error is firing(update failed – Neymar Da Silva Dec 17 '15 at 12:27
  • So,the solution is if you can prevent calling future method from future then problem csn be solved. I think this is the only way – Ashwani Dec 17 '15 at 12:29
  • Yeah. But first of all could you please make me sure can we update one object pick list after update user object update. if so.... which way would be better – Neymar Da Silva Dec 17 '15 at 12:40
  • I have answered it below in detail. – Ashwani Dec 17 '15 at 12:44
1

Following on what @Ashwani said, above.

By looking at your code, it looks like you're updating Termination_Request__c in a trigger (synchronous context) and the users in a future method, which should be OK.

Note: I'm not familiar with the future syntax you used, whereby you declared a synchronous method inside the body of an aysnchronous method, but I assume that is working.

You have to be careful not to do any DML on Termination_Request__c inside the future, because this would fire your trigger again inside a future context. This will, in turn, try to call the future method again and cause the exception you see.

I don't see any DML on Termination_Request__c inside the deactivateUsers method, but I do see that you declare List<Termination_Request__c> terminationToupdateList, which you don't seem to use.

I find that, one of the best ways to debug things is to clean the code to reduce it to the bare minimum that will work, which exposes issues more clearly. You have some redundancy/dupliaction/unneded variables in your code, which is making it more difficult for you to find out.

You could simplify the deactivateUsers method to:

public static void  deactivateUsers(Set<id> conIds) {

    list<user> usrLst= [SELECT Id, IsPortalEnabled,IsActive
        FROM User
        WHERE Contactid IN: conIds AND (isActive = true OR isPortalEnabled = true)];  
    system.debug('deactivateUsers.usrLst==>'+usrLst);
    for(user u : usrLst) {
        u.IsActive = false;    
        u.IsPortalEnabled = false;
    }            
    update ursLst;
}

This achieves the same result and reduces clutter, and allows you to highlight where your issue is hopefully a bit better

0

Answering from bottom to top.

You can update set-up and non-setup object only by @future annot. method or by any other approach which breaks the transaction thread.

You cannot update set-up and non-setup together in single transaction.

So,the solution is if you can prevent calling future method from future then problem can be solved. Identify why future method calling other future method. May be a batch is calling future method. That is also not possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.