+ Start a Discussion
DodiDodi 

Bulk trigger using aggregate queries - unable to update in batch

I am trying to use some code from this post. I am trying to write a trigger that allows for bulk processing of counting attachments associated to a record based on the record change(not addition of the attachment). Below is my code that compliles, but I get a runtime error "Apex trigger WasteProfileAttachmentCount caused an unexpected exception, contact your administrator: WasteProfileAttachmentCount: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id a0fa0000006j8IAAAY; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = a0fa0000006j8IA) is currently in trigger WasteProfileAttachmentCount, therefore it cannot recursively update itself: []: Trigger.WasteProfileAttachmentCount: line 30, column 1"

 

I understand that I am not supposed to explicitly call update, on the same record. But how can I update in bulk?....below is the code.

 

trigger WasteProfileAttachmentCount on ProfileDocument__c (before update) {

    Set<Id> ids = new Set<Id>();
    ids.addAll(trigger.newMap.keySet());
    
    AggregateResult[] counts = [SELECT ParentId,count(id)attachments FROM Attachment WHERE ContentType = 'application/pdf' AND ParentId IN :ids GROUP BY ParentId];   
    
    List<ProfileDocument__c> toUpdate = new List<ProfileDocument__c>();
    
    for(AggregateResult ar : counts){
        ProfileDocument__c tempDocs = new ProfileDocument__c(Id=string.valueof(ar.get('ParentId')),Attachments__c=integer.valueof(ar.get('attachments')));
        toUpdate.add(tempDocs);
    }
    
    update toUpdate;

}

Best Answer chosen by Admin (Salesforce Developers) 
k_bentsenk_bentsen

The problem is following the practice of building a list of records to update requires a DML operation which will invoke any triggers of that object type. Using before triggers, you can directly apply new values to records without DML. See if the below change to your loops helps out:

 

for(AggregateResult ar : counts){
    for(ProfileDocument__c pd: Trigger.new){
        if(ar.get('ParentId') == pd.Id)
            pd.Attachments__c = integer.valueof(ar.get('attachments'))
    }
}

 Don't forget to remove the update line :)

 

All Answers

k_bentsenk_bentsen

The problem is following the practice of building a list of records to update requires a DML operation which will invoke any triggers of that object type. Using before triggers, you can directly apply new values to records without DML. See if the below change to your loops helps out:

 

for(AggregateResult ar : counts){
    for(ProfileDocument__c pd: Trigger.new){
        if(ar.get('ParentId') == pd.Id)
            pd.Attachments__c = integer.valueof(ar.get('attachments'))
    }
}

 Don't forget to remove the update line :)

 

This was selected as the best answer
DodiDodi

Thanks, your code suggestion appears to works great!