I have two objects linked by a lookup. The objects are one-to-one and neither should exist without its counterpart. When one is deleted, I need the other to be deleted as well.

My plan was to put some logic in each objects' trigger. Here's what Obj 1's trigger looks like:

if (Trigger.isAfter && Trigger.isDelete) {
    for (Obj_1__c obj: Trigger.Old) {
        delete [select id from Obj_2__c where Obj_1__c = : obj.Id];

The problem with this is that the lookup is cleared out before the After Delete trigger, since the deletion of Obj 1 has already taken place. And I'm afraid using a Before Delete trigger will cause similar logic in Obj 2's trigger to create a loop, attempting to delete its Obj 1 lookup.

Is there a better way to delete records that are paired by a lookup? I know there's a built-in cascade delete, but you have to submit a ticket to SF to enable that functionality.

  • Which object in this scenario is the lookup field on? Or do you have a lookup field on each object that points to the other? – JCD Sep 18 '15 at 21:36
  • @JCD The lookup is on Obj_2__c. – CDelaney Sep 19 '15 at 21:57

The trick is to store the values beforehand. Simply set up a static variable to hold the old values before deletion, then delete them after deleting:

public class Stash {  // Don't use statics in triggers. They behave oddly.
    public static SObject[] pendDeletes;

// Trigger
trigger ... on ... (before delete, after delete) {
    if(Trigger.isBefore) {
        Stash.pendDeletes = [SELECT Id FROM Obj_2__c WHERE Obj_1__c IN :Trigger.old];
    } else {
        if(Stash.pendDeletes != null) {
            SObject[] temp = Stash.pendDeletes;
            Stash.pendDeletes = null;  // Avoid recursion
            delete temp;
  • I had considered this approach so I'm happy to see the suggestion. Thanks! – CDelaney Sep 19 '15 at 22:09

You should avoid putting a query in a loop. Instead maybe something like this would work:

if (Trigger.isBefore && Trigger.isDelete) {
    List<Obj2> obj2List = new List<Obj2>();
    List<Id> idList = new List<Id>();
    for (Obj_1__c obj: Trigger.Old) {
    List<Obj2> obj2List = [SELECT Id FROM Obj2 WHERE Id IN: idList];
    if(obj2List != null){
        delete obj2List;
  • The query isn't the issue, so this doesn't solve anything. I understand it's not a best practice, but the objects are deleted one at a time, so I'm not concerned. – CDelaney Sep 19 '15 at 21:59

I think you should not allow user to delete child record. Deletion of parent should delete a child record, that way you can maintain clean data.

If you can change the relationship, change it master detail OR else raise a case with Salesforce Support to activate Cascade Delete for lookups. Also you'll need to restrict deletion of child records so that one has to delete the parent to auto delete the child.

You won't have to write any triggers.

  • For a good UX with this app I need to allow the user to delete from both the parent and the child (and since these are 1-to-1 the user doesn't see it as a parent-child). Using a master-detail might be an option though. Would you happen to know if the relationship type can change for a field that's already published to a managed package? – CDelaney Sep 19 '15 at 22:04

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.