I'm having an issue trying to design a for loop in a batch process for deleting apex share records. If anyone could help it'd be much appreciated.

The basic scenario is as follows. First, there is a master-detail between objects Parent and Child. When a child is created, it's Status__c picklist field is set to 'Active' and a Parent__Share record is created for it (in another trigger). The UserOrGroupId on the Parent__Share record is equivalent to a user lookup Team_Member__c field on the child object (thus giving that user access via the Parent__Share).

The class below should be called when the Status__c picklist field is changed to 'Inactive'. In that case, any Parent__Share record where the UserOrGroupId equals Team_Member__c on a Child record and where the Child has a Status of 'Inactive', and where they share the same Parent should be deleted..

Two questions: 1) Am I going about this in right way? Is using embedded for loops the correct approach? 2) What is wrong with my code?

Thank you to anyone who can help :-)

global class DeleteShares implements Database.Batchable<sObject> {

global Database.QueryLocator start(Database.BatchableContext BC){
    return Database.getQueryLocator([SELECT Id FROM Parent__c]);  

global void execute(Database.BatchableContext BC, List<sObject> scope){

    // Create map for Parent object
    Map<Id, Parent__c> parentMap = new Map<Id, Parent__c>((List<Parent__c>)scope);

    //Get all existing share records       
    List<Parent__Share> currentShares = [SELECT Id, UserOrGroupId FROM Parent__Share WHERE ParentId IN 
        AND RowCause = 'Team_Member_Access__c'];

    // Create list for child object
    List<Child__c> childList = new List<Child__c>();
    childList = [SELECT Id, Parent__c, Status__c, Team_Member__c FROM Child__c WHERE Status__c = 'Inactive'];

    //When a child record is created, a trigger fires that creates a share record (Parent__Share)
    //When created, the child record is also given a Status of 'Active' in a picklist field Status__c on the child record

    // My matching loop. 
    // When the Status on the child record is changed from 'Active' to 'Inactive',
    // this class will be called. All share records with RowCause= 'Team_Member_Access__c' 
    // and a child record that has Status 'Inactive' should be deleted
    for (Parent__Share s: currentShares){
      for (Child__c c: childList){
          if (parentMap.containsKey(c.Parent__c) && (s.UserOrGroupId == c.Team_Member__c)){

              Delete s;


    global void finish(Database.BatchableContext BC){}



The first thing I see wrong with the code is that you have a DML operation inside a for loop and should be changed to:

for (Parent__Share s: currentShares){
      for (Child__c c: childList){
          if (parentMap.containsKey(c.Parent__c) && (s.UserOrGroupId == c.Team_Member__c)){
 delete shareRecordsToDelete;

In the code you need to declare a list that will hold share records, List<Parent__Share> shareRecordsToDelete = new List<Parent__Share>();

This will then remove the DML operation outside the for loop, preventing you to hit the limit.

Can I also ask, could this SOQL query be limited in terms of records returned SELECT Id FROM Parent__c ? It might be that you don't need all the records in the Parent__c object and it will avoid in the future hitting the limit of 50.000 records return from the database.

  • Thank you Mihai! I think your solution is a really good point, I've modified my code to integrate your idea. In response to your question about the Query, I am following, to a degree, this model salesforce.com/us/developer/docs/apexcode/Content/… . I agree, I need to edit my code further because it still doesn't work. The error is that there was a duplicate ID for the Parent__Share – rwegner7 Jan 9 '15 at 16:53

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.