1

Background: We have a Managed Package that syncs data with our system via Bulk Data Loads. Occasionally, based on a change in Salesforce, record(s) are sent to the external system and then subsequently deleted in Salesforce by the sync tool. Looking at the Bulk Data Loader Jobs, I see that they are deleting lots of object records before inserting new version of those records.

When their Bulk Data Load inserts new records, they correctly run through the Before/After insert code on that object. However, when their Bulk Data Load deletes existing records it is failing to run through my Before/After Delete methods entirely. It isn't even posting the system debugs acknowledging Before/After delete.


Assumptions: At this point, I thought maybe the bulk data loader deletion was doing a HARD delete, and that maybe HARD deletes didn't run apex. To test this, I used Data Loader, set it to use the Bulk API, and used the HARD DELETE button to manually delete one of the records. However, when I did the hard delete via data loader, it ran the before/after delete code as expected.


So far I have determined that:

  1. Manual deletion runs the code
  2. Deletion via Apex runs the code
  3. Standard Deletion via Data Loader runs the code
  4. Hard Deletion via Data loader runs the code
  5. Deletion when controlled by the Sync product DOES NOT run the code.

Question: Is there something I am missing here that would easily explain how/why these deletions aren't running through my code, or even posting the system debug to indicate that it reached the delete methods? We use a SFDC Trigger Framework (https://github.com/kevinohara80/sfdc-trigger-framework) that handles all of the different trigger mechanics, and our trigger is setup to run on all trigger conditions. I KNOW they are deleting the records because when I refresh the UI for those records it says they have been deleted... but I can't for the life of me figure out how and/or why they are bypassing my trigger.


Code Below for Context

Trigger:

trigger MasterSubscriptionProductChargeTrigger on Zuora__SubscriptionProductCharge__c (before insert, before update, before delete, after insert, 
                            after update, after delete, after undelete) {
    new MasterSubscriptionProductChargeTrigHdlr().run();                            
}

Handler:

public with sharing class MasterSubscriptionProductChargeTrigHdlr extends TriggerHandler{
    Zuora__SubscriptionProductCharge__c[] newList, oldList;
    Map<Id, Zuora__SubscriptionProductCharge__c> newMap, oldMap;

    public MasterSubscriptionProductChargeTrigHdlr() {
        super();
            newList  = (List<Zuora__SubscriptionProductCharge__c>) Trigger.new;
            oldList  = (List<Zuora__SubscriptionProductCharge__c>) Trigger.old;
            newMap  = (Map<Id, Zuora__SubscriptionProductCharge__c>) Trigger.newMap;
            oldMap  = (Map<Id, Zuora__SubscriptionProductCharge__c>) Trigger.oldMap;
    }
    protected override void beforeInsert(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsInserting - Before');

            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsInserting - Before');
        }

        protected override void beforeUpdate(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsUpdate - Before');

            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsUpdate - Before');
        }

        protected override void beforeDelete(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsDeleting - Before');

            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsDeleting - Before');
        }

        protected override void afterInsert(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsInserting - After');
            // CODE HERE - RUNNING
            // CODE HERE - RUNNING
            // CODE HERE - RUNNING
            // CODE HERE - RUNNING
            // CODE HERE - RUNNING
            // CODE HERE - RUNNING
            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsInserting - After');
        }
        protected override void afterUpdate(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsUpdate - After');

            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsUpdate - After');
        }
        protected override void afterDelete(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsDeleting - After');
            // CODE HERE - NOT RUNNING
            // CODE HERE - NOT RUNNING
            // CODE HERE - NOT RUNNING
            // CODE HERE - NOT RUNNING
            // CODE HERE - NOT RUNNING
            // CODE HERE - NOT RUNNING    
            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsDeleting - After');
        }
        protected override void afterUndelete(){
            system.debug('Start MasterSubscriptionProductChargeTrigHdlr IsUndeleting');

            system.debug('End MasterSubscriptionProductChargeTrigHdlr IsUndeleting');
        }

       /////////////////////////////////////////////////////////////////////////////////////////////

}
0

We spoke with the creators of the Managed Package and, through some investigation, we learned that the records that are being deleted are actually being deleted because they are detail records to a Master-Detail relationship where the relationship is defined to delete child records when the master is deleted.

Apparently when a Master record is deleted and causes a cascade deletion of child records, those child records do not run through Before/After Delete Triggers.

  • Yup this is documented behavior – Eric Dec 12 '17 at 8:41

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.