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
Holly Havelka 10Holly Havelka 10 

Help with Apex Sharing Trigger

Hi All,

I have the below trigger, and what I want to do is pull in the name of the group based on a field on the contact record where the after insert/after update is taking place.  The field is an account lookup field on contact and is named: Acct__c.  I want this to happen dynamically vs. having to hard code the name of the group.
trigger ContactMakePublicTrigger on Contact (after insert, after update) {
  
  ID groupId = [select id, Name from Group where Name = 'Cincinati User'].id;
    
  // inserting new records
  if (Trigger.isInsert) {
	         
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}
Any thoughts on how to rework the trigger to get the name of the lookup field dynamically?
 
Best Answer chosen by Holly Havelka 10
Holly Havelka 10Holly Havelka 10
Raj,

I got this trigger to work correctly, here is my updated code:
 
trigger ContactMakePublicTrigger on Contact (after insert, after update) {
 
    // Get the Account Name Details
    Set<Id> AcctId = new Set<Id>();
    List<Account> AccountLists = new List<Account>();
    Map<Id,String> AccountNameMap = new Map<Id,String>();
    
    for(Contact con : trigger.new)
    {
     
     if(con.AccountId != null)
     {
        AcctId.add(con.AccountId);
     }

    }
     
     if(AcctId.size() > 0)
     {
         AccountLists  = [select Id,name from Account where Id IN: AcctId];
     }

    for(Account acc :AccountLists  )
    {
        AccountNameMap.put(acc.id,acc.Name);
    }
    
    // Get the Group Details
    List<Group> groups = [SELECT Email,Id,Name FROM Group];

    Map<String,Id> GroupMap = new MAp<String,Id>();
    for( Group grp:groups)
    {
    	if(grp.Name != null && grp.Name != '')
    	{
        	GroupMap.put(grp.Name,grp.Id);
    	}
    }
  
  // inserting new records
  if (Trigger.isInsert) {
             
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;       
        if(GroupMap.containsKey(AccountNameMap.get(contact.accountId)))
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.accountId));   
        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        if(GroupMap.containsKey(AccountNameMap.get(contact.accountId)))
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.accountId));   
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}

 

All Answers

pankul guptapankul gupta
One Possible Solution Can be:
Get the list of all the groups in a List Group Object and then apply a for loop on that List based Group Object and then write the after logic inside the for Loop starting from //inserting records as in the code shared by you.

Regards,
Pankul
Maharajan CMaharajan C
Hi Holly,

Your code shoulde be like below:

Try the below changes:

trigger ContactMakePublicTrigger on Contact (after insert, after update) {
  
  //ID groupId = [select id, Name from Group where Name = 'Cincinati User'].id;
  // Get the Group Details
  
    List<Group> groups = [SELECT Email,Id,Name FROM Group];
    system.debug('@@@ groups'+groups.size());

    //Contact con = [select id, Name,Acct__r.Name from contact where id =: '0032800000UUC9U'];
    //system.debug('@@@ Account ' + con.Acct__r.Name );

    Map<String,Id> GroupMap = new MAp<String,Id>();
    for( Group grp:groups)
    {
    if(grp.Name != null && grp.Name != '')
    {
        GroupMap.put(grp.Name,grp.Id);
    }
    }

  

   
  // inserting new records
  if (Trigger.isInsert) {
             
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        //cs.UserOrGroupId =  groupId;
        if(GroupMap.containsKey(cs.Acct__r.Name))
        {
            cs.UserOrGroupId =  GroupMap.get(cs.Acct__r.Name);   // Check here if you can able to access the Account name of lookup field as like this otherwisw we have query this Account from DB then get the Name with the help of Map,Soql mostly the above will work

        }    
        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        if(GroupMap.containsKey(cs.Acct__r.Name))
        {
            cs.UserOrGroupId =  GroupMap.get(cs.Acct__r.Name);
        }    
        //cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}


Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!

Thanks,
Raj

 
Holly Havelka 10Holly Havelka 10
Raj, thanks for looking at this one.  I am getting an error that says 'variable does not exist: Acct__r.Name' on all four lines.  
Maharajan CMaharajan C
Hi Holly,

Sorry its my mistake:

trigger ContactMakePublicTrigger on Contact (after insert, after update) {
  
  //ID groupId = [select id, Name from Group where Name = 'Cincinati User'].id;
  // Get the Group Details
  
    List<Group> groups = [SELECT Email,Id,Name FROM Group];
    system.debug('@@@ groups'+groups.size());

    //Contact con = [select id, Name,Acct__r.Name from contact where id =: '0032800000UUC9U'];
    //system.debug('@@@ Account ' + con.Acct__r.Name );

    Map<String,Id> GroupMap = new MAp<String,Id>();
    for( Group grp:groups)
    {
    if(grp.Name != null && grp.Name != '')
    {
        GroupMap.put(grp.Name,grp.Id);
    }
    }
  

   
  // inserting new records
  if (Trigger.isInsert) {
             
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        //cs.UserOrGroupId =  groupId;
        if(GroupMap.containsKey(contact.Acct__r.Name))
        {
            cs.UserOrGroupId =  GroupMap.get(contact.Acct__r.Name);   // Check here if you can able to access the Account name of lookup field as like this otherwisw we have query this Account from DB then get the Name with the help of Map,Soql mostly the above will work

        }    
        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        if(GroupMap.containsKey(contact.Acct__r.Name))
        {
            cs.UserOrGroupId =  GroupMap.get(contact.Acct__r.Name);
        }    

        //cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}


Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!


Thanks,
Raj
Maharajan CMaharajan C
Hi Holly,

Small update to avoid the null exception due to cross object reference field acct__r.name:

trigger ContactMakePublicTrigger on Contact (after insert, after update) {
  
  //ID groupId = [select id, Name from Group where Name = 'Cincinati User'].id;
 
    // Get the Account Name Details
    Set<Id> AcctId = new Set<Id>();
    List<Account> AccountLists = new List<Account>();
    Map<Id,String> AccountNameMap = new Map<Id,String>(); 
    for(Contact con : trigger.new)
    {
     
     if(con.Acct__c != null)
     {
        system.debug('@@@ Acct__c '+con.Acct__c);
        system.debug('@@@ Acct__c Name '+ con.Acct__r.Name);
        AcctId.add(con.Acct__c);
     }

    }
     
     if(AcctId.size() > 0)
     {
         AccountLists  = [select Id,name from Account where Id IN: AcctId];
     }

    for(Account acc :AccountLists  )
    {
        AccountNameMap.put(acc.id,acc.Name);
    }
    system.debug('@@@ AccountNameMap values'+AccountNameMap.values());

    
    
    // Get the Group Details
    List<Group> groups = [SELECT Email,Id,Name FROM Group];
    system.debug('@@@ groups'+groups.size());

    //Contact con = [select id, Name,Acct__r.Name from contact where id =: '0032800000UUC9U'];
    //system.debug('@@@ Account ' + con.Acct__r.Name );

    Map<String,Id> GroupMap = new MAp<String,Id>();
    for( Group grp:groups)
    {
    if(grp.Name != null && grp.Name != '')
    {
        GroupMap.put(grp.Name,grp.Id);
    }
    }
  

   
  // inserting new records
  if (Trigger.isInsert) {
             
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        //cs.UserOrGroupId =  groupId;
        
        if(AccountNameMap.containsKey(contact.Acct__c))
        {
            if(GroupMap.containsKey(AccountNameMap.get(contact.Acct__c))
            {
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.Acct__c));   
            } 
        }

        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        if(AccountNameMap.containsKey(contact.Acct__c))
        {
            if(GroupMap.containsKey(AccountNameMap.get(contact.Acct__c))
            {
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.Acct__c));   
            } 
        }

        //cs.UserOrGroupId =  groupId;
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}


Can you please Let me know if it helps or not!!!

If it helps don't forget to mark this as a best answer!!!

Thanks,
Raj
Holly Havelka 10Holly Havelka 10
Hi Raj,  I put in your updated code, but I am getting the following error now:
ContactMakePublicTrigger: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [User/Group]: [User/Group]: Trigger.ContactMakePublicTrigger: line 121, column 1

 
Maharajan CMaharajan C
Hi Holly,

I have the one question here:

How are you compare the group and acct__c field. is that acct__c and group name is same?

How you want to get the group id? based on which field.

Thanks,
Raj
Holly Havelka 10Holly Havelka 10
Raj,

The acct__c.name should equal the group name.  The group ID would be once you find the group.name which is equal to acct__c.name, then the group.id would come from the identified group name.
Holly Havelka 10Holly Havelka 10
Raj,

I got this trigger to work correctly, here is my updated code:
 
trigger ContactMakePublicTrigger on Contact (after insert, after update) {
 
    // Get the Account Name Details
    Set<Id> AcctId = new Set<Id>();
    List<Account> AccountLists = new List<Account>();
    Map<Id,String> AccountNameMap = new Map<Id,String>();
    
    for(Contact con : trigger.new)
    {
     
     if(con.AccountId != null)
     {
        AcctId.add(con.AccountId);
     }

    }
     
     if(AcctId.size() > 0)
     {
         AccountLists  = [select Id,name from Account where Id IN: AcctId];
     }

    for(Account acc :AccountLists  )
    {
        AccountNameMap.put(acc.id,acc.Name);
    }
    
    // Get the Group Details
    List<Group> groups = [SELECT Email,Id,Name FROM Group];

    Map<String,Id> GroupMap = new MAp<String,Id>();
    for( Group grp:groups)
    {
    	if(grp.Name != null && grp.Name != '')
    	{
        	GroupMap.put(grp.Name,grp.Id);
    	}
    }
  
  // inserting new records
  if (Trigger.isInsert) {
             
    List<ContactShare> sharesToCreate = new List<ContactShare>();

    for (Contact contact : Trigger.new) {
        
      if (contact.Make_Public__c == true) {

        // create the new share for group
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;       
        if(GroupMap.containsKey(AccountNameMap.get(contact.accountId)))
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.accountId));   
        sharesToCreate.add(cs);

      }
    }

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  // updating existing records
  } else if (Trigger.isUpdate) {

    List<ContactShare> sharesToCreate = new List<ContactShare>();
    List<ID> shareIdsToDelete = new List<ID>();

    for (Contact contact : Trigger.new) {

      // if the record was public but is now private -- delete the existing share
      if (Trigger.oldMap.get(contact.id).Make_Public__c == true && contact.Make_Public__c == false) {
        shareIdsToDelete.add(contact.id);

      // if the record was private but now is public -- create the new share for the group
      } else if (Trigger.oldMap.get(contact.id).Make_Public__c == false && contact.Make_Public__c == true) {
        
        // create the new share with read/write access
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Edit';
        cs.ContactId = contact.Id;
        if(GroupMap.containsKey(AccountNameMap.get(contact.accountId)))
                cs.UserOrGroupId =  GroupMap.get(AccountNameMap.get(contact.accountId));   
        sharesToCreate.add(cs);

      }

    }

    // do the DML to delete shares
    if (!shareIdsToDelete.isEmpty())
      delete [select id from ContactShare where ContactId IN :shareIdsToDelete and RowCause = 'Manual'];

    // do the DML to create shares
    if (!sharesToCreate.isEmpty())
      insert sharesToCreate;

  }

}

 
This was selected as the best answer