Example: Write a trigger logic to prevent Account from Deleting if it has Opportunities associated to it.
Solution
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 newAccount : trigger.old) {
newAccount.addError('Connect delete as it has Opportunities');
}
}
} Scenario
Sales teams often want to protect Accounts that already have deals. If someone deletes such an Account, its Opportunity history can be lost. This trigger stops the deletion and shows an error message instead.
How the code works
- The trigger runs in the
before deletecontext, so it can block the delete before anything is removed. Trigger.oldholds the Accounts the user is trying to delete.- A SOQL query finds Opportunities whose
AccountIdmatches those Accounts. - If any Opportunity is found,
addError()is called on the Account. This cancels the delete and shows the message to the user.
Limitations of the code above
- Bulk deletes: if you delete 10 Accounts and only one has Opportunities, this version blocks all 10, because the error is added to every Account in the batch.
- Operator: the query uses
=:with a list.IN :is the correct operator for lists and is easier to read. - Message: the error text is unclear. “Cannot delete this Account because it has related Opportunities.” is better for users.
- Redundant check:
!oppr.isEmpty()andoppr.size() > 0mean the same thing.
Improved version (bulk-safe)
trigger AccountTrigger on Account (before delete) {
Set<Id> accountsWithOpps = new Set<Id>();
for (AggregateResult ar : [
SELECT AccountId
FROM Opportunity
WHERE AccountId IN :Trigger.oldMap.keySet()
GROUP BY AccountId
]) {
accountsWithOpps.add((Id) ar.get('AccountId'));
}
for (Account acc : Trigger.old) {
if (accountsWithOpps.contains(acc.Id)) {
acc.addError('Cannot delete this Account because it has related Opportunities.');
}
}
} This blocks only the Accounts that have Opportunities, and uses one query no matter how many Accounts are deleted.
How to test
- Create an Account with one Opportunity and try to delete it. You should see the error.
- Create an Account with no Opportunities and delete it. It should delete normally.
- From a list view, select both Accounts and delete them together. Only the one with Opportunities should be blocked.
FAQ
Why use a before trigger?
addError() only prevents a record from saving or deleting when it is called before the database operation.
Does this work for bulk deletes from Data Loader?
Yes. Triggers run for bulk operations, which is why the improved version avoids a query inside a loop.
Can I do this without code?
Not reliably. Validation rules do not run on delete, so a trigger is the usual approach.
trigger getAccountRelatedOpportunity on Account (before delete) {
Set accountIdsToDelete = new Set();
if (Trigger.isBefore && Trigger.isDelete) {
for (Account acc : Trigger.old) {
accountIdsToDelete.add(acc.Id);
}
// Query all Opportunities linked to the Accounts being deleted
Set accountsWithOpportunities = new Set();
for (Opportunity opp : [SELECT Id, AccountId FROM Opportunity WHERE AccountId IN :accountIdsToDelete]) {
accountsWithOpportunities.add(opp.AccountId);
}
// Add error on Accounts that have related Opportunities
for (Account acc : Trigger.old) {
if (accountsWithOpportunities.contains(acc.Id)) {
acc.addError(‘Cannot delete Account because related Opportunities exist.’);
}
}
}
}
trigger getAccountRelatedOpportunity on Account (before delete) {
Set accountIdsToDelete = new Set();
if (Trigger.isBefore && Trigger.isDelete) {
for (Account acc : Trigger.old) {
accountIdsToDelete.add(acc.Id);
}
// Query all Opportunities linked to the Accounts being deleted
Set accountsWithOpportunities = new Set();
for (Opportunity opp : [SELECT Id, AccountId FROM Opportunity WHERE AccountId IN :accountIdsToDelete]) {
accountsWithOpportunities.add(opp.AccountId);
}
// Add error on Accounts that have related Opportunities
for (Account acc : Trigger.old) {
if (accountsWithOpportunities.contains(acc.Id)) {
acc.addError(‘Cannot delete Account because related Opportunities exist.’);
}
}
}
}