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 Answer 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. Commented Nov 9, 2017 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 :)
    – itsmebasti
    Commented Nov 9, 2017 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 ;)
    – itsmebasti
    Commented Nov 9, 2017 at 15:44
  • 1
    It'll always be 1 to 1. But yeah, I think I understand. Thanks for you help! Commented Nov 9, 2017 at 16:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .