1

I'm new to Apex and code...

I have two objects that relate to each other with a before delete trigger on each. If object A is deleted, it's trigger will also delete object B. If Object B is deleted, it's trigger will also delete Object A.

First Trigger

trigger TateTimeEntryNewTrigger on Time_Entry_New__c (before delete) {
List<Id> idsToQuery = new List<Id>{};
for(Time_Entry_New__c ten : Trigger.old) {
    idsToQuery.add(ten.Id);
}

SVMXC__Service_Order_Line__c[] wdsToDelete = [SELECT Id FROM SVMXC__Service_Order_Line__c WHERE Time_Entry_New__c IN :idsToQuery];

delete wdsToDelete;}

Second Trigger

trigger WorkDetailTrigger on SVMXC__Service_Order_Line__c (before delete) {
List<Id> idsToQuery = new List<Id>{};
for(SVMXC__Service_Order_Line__c wd : Trigger.old) {
    idsToQuery.add(wd.Id);
}

Time_Entry_New__c[] tenToDelete = [SELECT Id FROM Time_Entry_New__c WHERE Work_Details__c IN :idsToQuery];

delete tenToDelete;}

This is giving me a recursive error where it's causing both triggers to fire. I know that I could create a checkbox and have 1 trigger check it and have the other trigger require that it be false to fire, but I was wondering if there was a smarter way to code this.

Here's the error when the second trigger fires first:

First exception on row 0 with id a1J29000000Bnk1EAC; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = a1J29000000Bnk1) is currently in trigger WorkDetailTrigger, therefore it cannot recursively delete itself: [] Trigger.TateTimeEntryNewTrigger: line 9, column 1: []: Trigger.WorkDetailTrigger: line 9, column 1".

1

First, it's bad to execute code in triggers, the best would be to write a Trigger handler class for both cases and add a Boolean to check if the other already executed. You can also do the IN statement directly on the list:

public class WorkDetailTriggerHanlder {
    public static Boolean alreadyExecuted = false;

    public void onBeforeDelete(List<SVMXC__Service_Order_Line__c> deleted) {
        alreadyExecuted = true;

        if(!TateTimeEntryNewTriggerHanlder.alreadyExecuted) {
            delete [SELECT Id FROM Time_Entry_New__c WHERE Work_Details__c IN :deleted];
        }
    }
}

trigger WorkDetailTrigger on SVMXC__Service_Order_Line__c (before delete) {
    new WorkDetailTriggerHanlder().onBeforeDelete(Trigger.old);
}

One looks like this, the other vice versa.

4
  • Thanks, I'll adjust my code to execute this way. When I use your code, I get an error that "variable does not exist: TimeTimeEntryNewTrigger" Do I need a statement at the top declaring that it's a trigger? It's spelled correctly. – Micah Perry Nov 9 '17 at 14:50
  • Oh sure, replace it with the handler you write for it: TateTimeEntryNewTriggerHanlder. You need to create one of them first, add the boolean and save it, else you will end in a recursive cycle not beeing able to save one of them :) – Basti Nov 9 '17 at 14:52
  • @MicahPerry btw take care if it is not a 1 to 1 relationship. In this case, you might need to filter for elements, that were already deleted and execute the trigger for all that weren't included in the first execute, it's getting comlex here, I know ;) – Basti Nov 9 '17 at 15:44
  • 1
    It'll always be 1 to 1. But yeah, I think I understand. Thanks for you help! – Micah Perry Nov 9 '17 at 16:07

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.