Trigger – Prevent Account from Deletion if it has related Opportunities

Prevent Account from Deletion if it has related Opportunities
Prevent Account from Deletion if it has related Opportunities

Hello dear coders, here is another apex trigger scenario – If the account has related opportunities then we should not able to delete that account. Here is the code for it. Do watch the video for detail understanding.

				
					trigger AccountTrigger2 on Account (before delete) {

    if(Trigger.isBefore && Trigger.isDelete) { 
        
        List<Opportunity> oppr = [SELECT ID, AccountId From Opportunity Where AccountId =: Trigger.old];
        
        if(!oppr.isEmpty() && oppr.size() > 0 ) { 
            for(Account acc: Trigger.old ) { 
                acc.addError('You cannot delete this Account it has  Opportunity related to it.');
            }
        }
    }
    
}
				
			

In this video we have discussed the trigger in detail.

How this trigger works

This is a before delete trigger on the Account object. Salesforce fires it just before an Account is removed, which is the right moment to stop the delete. Trigger.old holds the Accounts that the user is trying to delete. The trigger queries the Opportunities linked to those Accounts, and if any exist, it calls addError() on the Account. Calling addError() in a before trigger blocks the delete and shows the message to the user.

Step by step

  1. The user clicks Delete on an Account (or a bulk delete runs).
  2. The before delete event fires and Trigger.old contains the records about to be deleted.
  3. A SOQL query looks for Opportunities whose AccountId matches those Accounts.
  4. If Opportunities are found, addError() stops the delete and the user sees the custom message.
  5. If no Opportunities are found, the delete goes through normally.

A bulk-safe version

The code above shows the idea. In real projects, a trigger should handle many records at once (for example, a data loader deleting 200 Accounts) and should only block the Accounts that really have Opportunities. This version does both with a single query:

trigger AccountTrigger2 on Account (before delete) {
    // Collect the Accounts that have at least one related Opportunity
    Set<Id> accountsWithOpps = new Set<Id>();
    for (Opportunity opp : [SELECT AccountId FROM Opportunity
                            WHERE AccountId IN :Trigger.oldMap.keySet()]) {
        accountsWithOpps.add(opp.AccountId);
    }

    // Block only those Accounts
    for (Account acc : Trigger.old) {
        if (accountsWithOpps.contains(acc.Id)) {
            acc.addError('You cannot delete this Account because it has Opportunities related to it.');
        }
    }
}

Test class

Always cover a trigger with tests. This test checks both cases: delete is blocked when an Opportunity exists, and allowed when it does not.

@isTest
private class AccountTrigger2Test {
    @isTest
    static void blocksDeleteWhenOpportunityExists() {
        Account acc = new Account(Name = 'Test Account');
        insert acc;
        insert new Opportunity(Name = 'Test Opp', AccountId = acc.Id,
                               StageName = 'Prospecting',
                               CloseDate = Date.today().addDays(30));

        Test.startTest();
        Database.DeleteResult result = Database.delete(acc, false);
        Test.stopTest();

        System.assert(!result.isSuccess(), 'Delete should be blocked');
    }

    @isTest
    static void allowsDeleteWhenNoOpportunity() {
        Account acc = new Account(Name = 'Lonely Account');
        insert acc;

        Test.startTest();
        Database.DeleteResult result = Database.delete(acc, false);
        Test.stopTest();

        System.assert(result.isSuccess(), 'Delete should be allowed');
    }
}

Interview tips and common questions

  • Why before delete and not after delete? In a before trigger the record is still in the database, so addError() can stop the delete. After delete, it is too late.
  • Can this be done without code? Yes. A record-triggered Flow that runs before the record is deleted can look up related Opportunities and stop the delete with a Custom Error element. Mention both the trigger and the Flow approach in an interview to show you know the options.
  • Why use Trigger.oldMap.keySet()? It gives the Ids of all records in the batch, so one SOQL query handles up to 200 records and you stay within governor limits.
  • Why use a custom trigger for this? It gives you full control over the rule and the message shown to the user, and you can change the condition later, for example to block the delete only for open Opportunities.

If you want to see a similar scenario, browse the other Apex trigger scenarios on CodersBugs and try writing the same logic as a Flow to compare.

This Post Has 2 Comments

  1. sv

    why video is private

    1. admin

      We will make them public soon.

Leave a Reply