One of the most important principles in CRM data management is safeguarding relationships between key records. In Salesforce, the Account object acts as the anchor for many related objects—Contacts, Cases, and especially Opportunities, which hold your revenue-driving pipeline.
In this blog, we walk through a practical Apex trigger that prevents users from deleting Account records that have related Opportunities. This ensures that your sales pipeline, historical deal data, and business relationships are not unintentionally erased, preserving the integrity of your CRM and reporting structure.
The trigger executes in the before delete context, scanning each Account targeted for deletion to check whether it has existing Opportunities linked to it. If any are found, the deletion is blocked and the user is shown a clear error message.
🧠 Why This Trigger Is Essential
Deleting Accounts that still have associated Opportunities can create a ripple effect of data issues:
-
Historical deals disappear from reports and dashboards
-
Opportunity owners lose visibility into client history
-
Pipeline data becomes fragmented or inaccurate
-
Downstream integrations fail, especially if they rely on parent-child relationships
This trigger safeguards against such risks by enforcing a simple but effective rule: if there are Opportunities, the Account can’t be deleted.
With this validation in place:
-
You maintain complete historical records
-
You prevent broken relationships in your object model
-
Users receive immediate guidance on why the action is blocked
-
Your CRM retains its integrity for forecasting, reviews, and audits
It’s a crucial layer of defense for any Salesforce instance that handles deals, customer data, or revenue reporting.
🔍 What This Blog Covers
-
How to implement a before delete Apex trigger to check for child record presence
-
Why protecting parent-child relationships is critical in Salesforce
-
How to prevent deletion using user-friendly error messaging
-
How to wrap the logic in a clean, reusable handler class
-
Where this fits into your broader CRM data strategy
This validation ensures that no user can accidentally remove business-critical Accounts without first clearing or reassigning their dependent records.
🎯 Real-World Use Cases for This Trigger
-
Sales teams reviewing accounts and cleaning up data—without losing past deal history
-
Operations or finance teams validating billing records or deal timelines
-
Admin teams managing large data imports or deletions
-
Compliance-focused organizations preserving sales audit trails
-
Customer success teams using Account and Opportunity relationships for onboarding or retention analysis
Whether you’re managing B2B or B2C relationships, this trigger ensures your most valuable relationship data is preserved and protected.
👨💻 Developer & Admin Tips
Here’s how the logic works in simple terms:
-
The trigger fires before an Account is deleted
-
It checks each Account in the deletion list to see if any Opportunities exist
-
If at least one related Opportunity is found, the deletion is blocked
-
A clear error message is presented to the user so they understand what’s preventing the action
The logic is bulk-safe and designed for real-world scenarios, where multiple Accounts may be selected for deletion at once—either manually, via API, or through automation tools.
Using a handler class method keeps the logic clean, testable, and easily extendable. You can enhance this pattern to:
-
Block deletion only if Open Opportunities exist
-
Allow deletion if Opportunities are already Closed Won or Closed Lost
-
Send alerts or log deletion attempts for auditing
-
Provide user-friendly instructions on how to proceed (e.g., “Please reassign or archive related Opportunities before deletion.”)
It’s also recommended to test this trigger:
-
With single-record and bulk deletions
-
Using both admin and non-admin user profiles
-
Through API tools or automation scripts to validate consistent enforcement
🎥 Hands-On Demo – YouTube Playlist Available
Want to see this in action before you implement it? Visit the Salesforce Makes Sense YouTube playlist, where you’ll find a walkthrough that includes:
-
How to set up the trigger and handler
-
Testing scenarios for blocked and allowed deletions
-
UI demos showing user error messages
-
Best practices for extending or customizing the logic
This playlist is perfect for visual learners and anyone who wants to reinforce good Salesforce architecture habits in real-world use cases.
Solution:
trigger AccountTrigger on Account (before delete) {
if(Trigger.isDelete){ if(Trigger.isBefore){
AccountTriggerHandler.preventDelIfHasRelatedOpp(Trigger.old);
}
}
}
public class AccountTriggerHandler{
public static void preventDelIfHasRelatedOpp(List<Account> accList){ Set<Id>
idSet= new Set<Id>();
for(Account acc:accList){ idSet.add(acc.Id);
}
for(Account acc:[SELECT Id,(SELECT Id FROM Opportunities)FROM
Account WHERE Id IN:idSet]){ if(acc.Opportunities.size( ) > 0){ acc.addError(‘You can
not delete account where opportunities are available ‘); }
}
}
}