+ Start a Discussion
SrinuSrinu 

small error with trigger

Hi,

 

 I am working on a trigger, which changes the default "UserRoleId" to "Executive" from "User".

 

 To achieve above functionality, I have written trigger like below:

 

 

//
//Trigger that changes the default role of a new user that is NOT a Standard user from the “User” role to the “Executive” role
//

trigger ChnageDefaultUserRole on User(before insert,before update) {

    Set<Id> accIdSet = new Set<Id>();
    Set<Id> conIdSet = new Set<Id>();
    Map<Id, Contact> conMap = new Map<Id, Contact>();
    Map<Id, Id> userAcctMap = new Map<Id, Id>();
    
    for(user u:trigger.new) {
        if(Trigger.isInsert) {
            if(u.contactId != null){ 
              if(u.UserType != 'Standard'){
                conIdSet.add(u.contactId);
                userAcctMap.put(u.AccountId, u.Id);
               }
             }
        } else {
            if((u.AccountId != null)){
              if(u.UserType != 'Standard'){
                accIdSet.add(u.AccountId);
                userAcctMap.put(u.AccountId, u.Id);
               }
            }
        }
    }
        

    if(trigger.isinsert){
        List<UserRole> usrRole  = new List<UserRole>();
        if(!conIdSet.isEmpty()) {
            conMap = new Map<Id, Contact>([Select Id, AccountId, Account.Name from Contact where id IN: conIdSet]);
            for(Contact con: conMap.values()) {
                accIdSet.add(con.AccountId);
            }
        }    
    }
    //@future methods call out happens here
   if(accIdSet.size()!= Null && accIdSet.size() > 0){
     UserDefaultRoleChange.RoleChange(userAcctMap,accIdSet, conIdSet);
   }
}

  Class:

  

Public Class UserDefaultRoleChange{
    @future
     public static void RoleChange(Map<Id, Id> userAcctMap,Set<Id> accIdSet, Set<Id> conIdSet){
         Map<Id, Account> accInfoMap = new Map<Id, Account>([Select Id, Name,OwnerId from Account where Id IN: accIdSet]);
         Set<String> accNameSet = new Set<String>();
         Map<Id, Contact> conMap = new Map<Id, Contact>();
         List<User> UpdateUserList = new List<User>();
         
        for(Account acc: accInfoMap.Values()) {    
            accNameSet.add(acc.name + ' Customer Executive');
        }        
        
        List<UserRole> usrRole = [Select Id, Name From UserRole Where Name IN: accNameSet];
        Map<String, Id> usrMap = new Map<String, Id>();        
        for(UserRole ur: usrRole) {
            usrMap.put(ur.name, ur.Id); 
        }
        
        for(Account acct : accInfoMap.Values()){
          if((acct.name + ' Customer Executive') != null){
            if(usrMap.get(acct.name + ' Customer Executive') != null) {
                User us = new User();
                us.UserRoleId = usrMap.get(acct.name + ' Customer Executive');                
                UpdateUserList.add(us));
            }
          }
        }
        
        if(UpdateUserList.size() > 0)
           update UpdateUserList;           
        
     }
}

 I am geeting this error:

EXCEPTION_THROWN|[51]|System.DmlException: Update failed. First exception on row 0; first error: MISSING_ARGUMENT, Id not specified in an update call: []

 

//UpdateUserList.add(new User(Id=acct.OwnerId, UserRoleId = usrMap.get(acct.name + ' Customer Executive')));

    Error For Above line:

Class.UserDefaultRoleChange.RoleChange: line 50, column 1
00:35:06.428 (428327000)|FATAL_ERROR|System.DmlException: Update failed. First exception on row 0 with id 005600000018VhmAAE; first error: FIELD_INTEGRITY_EXCEPTION, role type must match user type: []

 

any hep would be appreciated?

 

 

SurekaSureka

Hi,

 

The following code shows that you are updating User record. But, here you are creating an instance of User record:

 

User us = new User();
us.UserRoleId = usrMap.get(acct.name + ' Customer Executive');               
UpdateUserList.add(us));

Instead Query the user whose Role needs to be updated and then change the role accordingly.

 

Eg.

User u = [select Id, Name, UserRoleId from User where Name=:'Testing User'];

UserRole ur= [select Id from UserRole where Name=:'COO'];
u.UserRoleId =ur.Id;
Update u;

 

Hope this helps.

 

Thanks

 

SrinuSrinu

Hi Sureka,

 Thanks for ur reply,

 

 I tried with below code as per ur suggestion, UserRoleId got assigned to corresponding role, but leads to this error:

 

User u = [Select Id, Name, UserRoleId from User where Name =:'Test L'];
UserRole ur= [select Id from UserRole where Name IN: accNameSet];
u.UserRoleId = ur.Id;
update u;

 

Error:

Trigger.ChnageDefaultUserRole: line 85, column 1
01:33:43.227 (227607000)|FATAL_ERROR|System.AsyncException: Future method cannot be called from a future or batch method: UserDefaultRoleChange.RoleChange(MAP<Id,Id>, SET<Id>, SET<Id>)

 

Can you look my entire code once, which i posted in first post and tell if i did any mistake with arguments passing to @furure method?

 

any help wud be appreciated?

 

 

SurekaSureka

Hi,

 

In your code, Future method is invoked in Loop. Problem is, You have a before Update trigger from where you are calling @Future method. In the Future method, you are updating the records, which will again invoke the trigger which inturn will call @Future method. And that's why you are getting this error.

 

To avoid this, before calling @Future method, check for the User Role and then call the @Future method.

 

Sample Code:

 

trigger UpdateByPass on User (before update)

{
for(User u:trigger.New)
{
if(u.ByPassVR__c!=true)
SampleClass.sampleMethod(u.Id);
}
}

 

In the above code, before calling future method, I have a check. Try the same way.

 

Thanks

 

SrinuSrinu

Hi Starz 26,

yes,

 

Still am working on it.

 

here is my latest trigger and @future method

 

//
//Trigger that changes the default role of a new user that is NOT a Standard user from the “User” role to the “Executive” role
//

trigger ChnageDefaultUserRole on User(after insert,after update) {

    Set<Id> accIdSet = new Set<Id>();
    Set<Id> conIdSet = new Set<Id>();
    Map<Id, Contact> conMap = new Map<Id, Contact>();
    Map<Id, Id> userAcctMap = new Map<Id, Id>();
    
    for(user u:trigger.new) {
        if(Trigger.isInsert) {
            if(u.contactId != null){ 
              if(u.UserType != 'Standard'){
                conIdSet.add(u.contactId);
               }
             }
        } else {
            if((u.AccountId != null)){
              if(u.UserType != 'Standard'){
                accIdSet.add(u.AccountId);
               }
            }
        }
    }
        

    if(trigger.isinsert){
        List<UserRole> usrRole  = new List<UserRole>();
        if(!conIdSet.isEmpty()) {
            conMap = new Map<Id, Contact>([Select Id, AccountId, Account.Name from Contact where id IN: conIdSet]);
            for(Contact con: conMap.values()) {
                accIdSet.add(con.AccountId);
            }
        }    
    }
    
       if(accIdSet.size()!= Null && accIdSet.size() > 0)
           UserDefaultRoleChange.RoleChange(userAcctMap,accIdSet, conIdSet);
   
}

 Controller class:

Public Class UserDefaultRoleChange{
    @future
     public static void RoleChange(Map<Id, Id> userAcctMap,Set<Id> accIdSet, Set<Id> conIdSet){
         Map<Id, Account> accMap = new Map<Id, Account>([Select Id, Name,OwnerId from Account where Id IN: accIdSet]);
         Set<String> accNameSet = new Set<String>();
         Map<Id, Contact> conMap = new Map<Id, Contact>([Select Id, AccountId, Account.Name from Contact where id IN: conIdSet]);
         List<User> UserList = new List<User>();
         List<User> UpdateUserList = new List<User>();
         
        for(Account acc: accMap.Values()) {    
            accNameSet.add(acc.name + ' Customer Executive');            
        }        
        
        List<UserRole> usrRole = [Select Id, Name From UserRole Where Name IN: accNameSet];
        Map<String, Id> usrMap = new Map<String, Id>();        
        for(UserRole ur: usrRole) {
            usrMap.put(ur.name, ur.Id); 
        }
        List<User> users = [Select Id, AccountId,ContactId,UserRoleId,UserType From User Where AccountId IN: accIdSet];        
        for(User us: users){
          if(us.UserType != 'Standard'){
               if(us.AccountId != null) {
                    Account acc = accMap.get(us.AccountId);                       
                    us.UserRoleId = usrMap.get(acc.name + ' Customer Executive'); 
               }else if(us.ContactId != null){
                    Contact tempCont = conMap.get(us.ContactId);
                    if(tempCont.Account.Name != null) {
                        us.UserRoleId = usrMap.get(tempCont.Account.Name + ' Customer Executive');
                    }
               }
          }
        }
        update Users;
        
     }
}

 I am getting this error for the above code: 

Trigger.ChnageDefaultUserRole: line 88, column 1
00:02:10.817 (817513000)|FATAL_ERROR|System.AsyncException: Future method cannot be called from a future or batch method: UserDefaultRoleChange.RoleChange(MAP<Id,Id>, SET<Id>, SET<Id>)
Here UserRoleId on User is a Custom picklist, and values are based on Account Name..
If suppose Account Name is : Test
then UserRoleId picklist values would be :
Test Customer User
Test Customer Manager
Test Customer Executive
I am working like this:
First Create An Account
then Contact For that Account
Then Create A USER for that Contact
while clikcing on SAVE button of USER, "UserRoleId" field should update with "Executive" role 
Why I have used @future annotation is role are generated dynamically after click on "Save" button of new user creation...
Any sample code with u guys, just share with me..
any help would be appreciated...!!!!
Starz26Starz26

So your future method gets called by the trigger, which updates users and calls the futur method again.

 

I would say:

 

1. Add Static variable to stop recursion

 

public static Boolean RoleChangeRunning = false;

 

public static Boolean recursionCheck(){

     return RoleChangeRunning;

}

 

then right before your update users call add RoleChangeRunning = true;

 

2. in trigger change:

 

if(accIdSet.size()!= Null && accIdSet.size() > 0)

to

 

if(accIdSet.size()!= Null && accIdSet.size() > 0 && !UserDefaultRoleChange.RecursionCheck())