function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ellsa JamesEllsa James 

How can I add a contact to a public group with Apex?

I am using the below code

trigger AddToPG on Contact (after insert, after update) {
    List<GroupMember> GMlist = new List<GroupMember>();
    for(Contact U : Trigger.New) {
        if(U.Add_to_Group__c == TRUE) {
            GroupMember GM = new GroupMember();
            GM.GroupId = '00Gg0000000afKH';
            GM.UserOrGroupId = U.Id;
            GMList.add(GM);        
        }
    }

        insert GMList;
    }

However, this is giving the below error

Error:Apex trigger AddToPG caused an unexpected exception, contact your administrator: AddToPG: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, User/Group ID: id value of incorrect type: 003g000000HfUsiAAF: [UserOrGroupId]: Trigger.AddToPG: line 12, column 1

I think this is because I am trying the set the contact ID where I should be using the User or Group ID. The contacts will be Partner users so they will have a user record. Are there any changes I can make to my trigger which will allow me to do this?
Best Answer chosen by Ellsa James
Shyam BhundiaShyam Bhundia
I just ran the code and got an 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".  This means that we cannot do an insert/update on a contact at the sametime as adding a user to a group.  

A work around is to use a future method which calls the code to add the user to the group.

the trigger:

trigger AddToPG on Contact (after insert, after update) {
   
    List<GroupMember> GMlist = new List<GroupMember>();
     Set<String> contactEmails = new Set<String>();
     for(Contact con : Trigger.New) { 
        //create a set with the contact email addresses
        contactEmails.add(con.email);
     }
 
     //query for the related users and put them in a map,
     //where the key is the email and the value is the user
     Map<String, User> emailUserMap = new Map<String, User> ();
     for(User aUser : [select id, email from User where email in : contactEmails]){
        emailUserMap.put(aUser.email, aUser);
     }
         system.debug(emailUserMap);
         List<Id> userIdList = new List<Id>();
    for(Contact con : Trigger.New) { 
      if(con.Add_to_Group__c == TRUE) {     
           
           userIdList.add(emailUserMap.get(con.email).id);
 
        } 
    }   

    //dymanically get the get group id.
    Group theGroup = [select id from Group where Name = 'test grp'];
    if(null != theGroup){
        //call the contact trigger helper if the group exists.  
        //This method adds the user to the group
        ContactTriggerHelper.addUsersToGroup(theGroup.id,userIdList );
    }
}

NOTE: I've made the way you get the group id dynamic, so please place 'test grp' with your group name.

the helper class:

public class ContactTriggerHelper{
    
    //future call to do the group adding.  the future call will spawn a new thread.
    @future
    public static void addUsersToGroup(String groupId, List<Id> userIds){
        List<GroupMember> GMlist = new List<GroupMember>();
        for(ID userId: userIds){
            GroupMember gm = new GroupMember();
            gm.GroupId = groupId;
            gm.UserOrGroupId = userId;
            gmList.add(GM);
        }
   
    
        if(gmList.size() > 0){
            insert gmList;
        }
    }
 
}




All Answers

Vatsal KothariVatsal Kothari
Hi Ellsa,

you can refer below code :

trigger AddToPG on Contact (after insert, after update) {
    
    List<GroupMember> GMlist = new List<GroupMember>();
            
    for(Contact con : Trigger.New) {  
	if(con.Add_to_Group__c == TRUE) {      
        	GroupMember gm = new GroupMember();
        	gm.GroupId = '00GG0000002ZWbi';
        	gm.UserOrGroupId = con.ownerId;
        	gmList.add(GM);
    	}  
    }     
            
    if(gmList.size() > 0) 
    {
    	insert gmList;
    }
}
If this solves your problem, kindly mark it as the best answer.

Thanks,
Vatsal

Ellsa JamesEllsa James
Hi Vatsal,

i have been able to save the code without error and I can also save the contact record without error but the contact is not added to the group. Any idea why?
Shyam BhundiaShyam Bhundia
The above code will add the contact OWNER to the group not the contact.

What you need to do is search for the corresponding user the contact relates to, once you have found the user, you can add that user to the group.  

How do you know what user is related to a contact?
Ellsa JamesEllsa James
Hi @Shyam Bhundia

That is what I am trying to do. The users I want to add to the groups will be partner users, so they will have a partner user record. the problem is, I don't know how to get the contacts related partner user ID. Any idea how I can get this?
Shyam BhundiaShyam Bhundia
Is there a way to identify which contact is related to a user?  For example will the contact have an email address, and that email address is the same its corresponding user?  If so you can do something like:

trigger AddToPG on Contact (after insert, after update) {
    
    List<GroupMember> GMlist = new List<GroupMember>();
     Set<String> contactEmails = new Set<String>();
     for(Contact con : Trigger.New) {  
        //create a set with the contact email addresses
        contactEmails.add(con.email);
     }

     //query for the related users and put them in a map, 
     //where the key is the email and the value is the user
     Map<String, User> emailUserMap = new Map<String, User> ();
     for(User aUser : [select id, email from User where email in : contactEmails]){
        emailUserMap.put(aUser.email, aUser);
     }
            
    for(Contact con : Trigger.New) {  
	   if(con.Add_to_Group__c == TRUE) {      
        	GroupMember gm = new GroupMember();
        	gm.GroupId = '00GG0000002ZWbi';
        	gm.UserOrGroupId = emailUserMap.get(con.email).id;
        	gmList.add(GM);
    	}  
    }     
            
    if(gmList.size() > 0){
    	insert gmList;
    }
}

If the user is created before the contact, you can create a new custom field (relatedUser__c) on the contact object which looks up to the related user.  If you can do this, then your code would look something like:

trigger AddToPG on Contact (after insert, after update) {
    
    List<GroupMember> GMlist = new List<GroupMember>();     
    for(Contact con : Trigger.New) {  
       if(con.Add_to_Group__c == TRUE) {      
            GroupMember gm = new GroupMember();
            gm.GroupId = '00GG0000002ZWbi';
            gm.UserOrGroupId = con.relatedUser__c;
            gmList.add(GM);
        }  
    }     
            
    if(gmList.size() > 0) {
        insert gmList;
    }
}

Also, ideally you should have the trigger on after insert only because currently the trigger will be called when ever the user is updated.

Ellsa JamesEllsa James
Hi Shyam,

Thanks but it is still not adding the User/Contact to the group. The record and trigger save without error but the Contact /User is not added to the Group. I am using the group ID from the URL on the Group detail page. Is this the correct ID? If so, is there any other reason why the user is not added to the group?
Ellsa JamesEllsa James
FYI, the email address is the same on the contact and user so I tried the code in your first suggestion.
Shyam BhundiaShyam Bhundia
I just ran the code and got an 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".  This means that we cannot do an insert/update on a contact at the sametime as adding a user to a group.  

A work around is to use a future method which calls the code to add the user to the group.

the trigger:

trigger AddToPG on Contact (after insert, after update) {
   
    List<GroupMember> GMlist = new List<GroupMember>();
     Set<String> contactEmails = new Set<String>();
     for(Contact con : Trigger.New) { 
        //create a set with the contact email addresses
        contactEmails.add(con.email);
     }
 
     //query for the related users and put them in a map,
     //where the key is the email and the value is the user
     Map<String, User> emailUserMap = new Map<String, User> ();
     for(User aUser : [select id, email from User where email in : contactEmails]){
        emailUserMap.put(aUser.email, aUser);
     }
         system.debug(emailUserMap);
         List<Id> userIdList = new List<Id>();
    for(Contact con : Trigger.New) { 
      if(con.Add_to_Group__c == TRUE) {     
           
           userIdList.add(emailUserMap.get(con.email).id);
 
        } 
    }   

    //dymanically get the get group id.
    Group theGroup = [select id from Group where Name = 'test grp'];
    if(null != theGroup){
        //call the contact trigger helper if the group exists.  
        //This method adds the user to the group
        ContactTriggerHelper.addUsersToGroup(theGroup.id,userIdList );
    }
}

NOTE: I've made the way you get the group id dynamic, so please place 'test grp' with your group name.

the helper class:

public class ContactTriggerHelper{
    
    //future call to do the group adding.  the future call will spawn a new thread.
    @future
    public static void addUsersToGroup(String groupId, List<Id> userIds){
        List<GroupMember> GMlist = new List<GroupMember>();
        for(ID userId: userIds){
            GroupMember gm = new GroupMember();
            gm.GroupId = groupId;
            gm.UserOrGroupId = userId;
            gmList.add(GM);
        }
   
    
        if(gmList.size() > 0){
            insert gmList;
        }
    }
 
}




This was selected as the best answer
Ellsa JamesEllsa James
Hi Shyam,

Thank you so much. It is working perfect. 1 more question. At the moment the trigger is firring based on -  "if(con.Add_to_Group__c == TRUE)" . I was thinking of having multiple checkboxes like this one. The idea is that depending on which checkbox is True, the contact(user) is added to the relevant group.

Example - 
If checkbox 1 is true = Add user to group 1
If checkbox 2 is true = Add user to group 2 etc....

Where in the code would I add the additional fields and Groups?
Shyam BhundiaShyam Bhundia
Great that it worked!

You need to add the further IF statments like in line 19.  You will also need to move all the logic to the future method as with the future annotation cannot take sObjects or objects as arguments.

So basically you pass a list of IDs to the future method and that does all the work.

Hope that helps.