0

I am trying to create a Trigger which will prevent deletion of Account which has atleast one contact linked to it. But its not working. Here is my code

trigger AccountDeleteonPrevention on Account (before delete) {
    if(Trigger.isBefore && Trigger.isDelete){
        for(Account acc: Trigger.old){
            if(acc.Contacts.size() > 0){
                acc.addError('You cannot delete this account');
            }
        }
    }
}

When I'm deleting Accounts which have contacts in my org they are getting deleted. Also I see that in debugging the value of account.Contacts.size() comes to be 0 which is strange. That's the reason my if block is not getting evaluated. I am unable to understand my mistake here. Please help

1
  • For those reading this in the future, the root of the issue here is that the record instances contained in the Trigger Context Variables do not have related data (nothing from parent records, nor from child records). You need to explicitly query for related data in triggers.
    – Derek F
    Commented Nov 9 at 13:39

4 Answers 4

2

If you want to add an error when you are trying to delete account than you need to

  1. Retrieve all related contacts

  2. Loop through each contact and add AccountId to Set

  3. Loop through accounts and add an error if account contains any contact

    trigger Account on Account (before delete) {
    
       if (Trigger.isBefore && Trigger.isDelete) {
          List<Contact> relatedContacts = [SELECT AccountId FROM Contact WHERE AccountId IN : Trigger.oldMap.keySet()];
    
          Set<Id> accIds = new Set<Id>();
          for (Contact contact : relatedContacts) {
              accIds.add(contact.accountId);
          }
    
          for (Account account : trigger.old) {
             if (accIds.contains(account.Id)) {
                 account.addError('You cannot delete this account');
             }
          }    
       }
    }
    

enter image description here

4
  • Thanks Kate it works. But I had a doubt. I saw an online example where a relationship SOQL query is done as follows: List<Account> acc=[select Name , (Select LastName from contacts) from Account Limit 10... then to get the no of contacts the following was done which directly gave the number of contacts for(Account acct:acc){ system.debug('####'+acct.contacts.size()); } So I was trying the same concept to get if size of this list of contacts is more than 0 means it has a contact so dont delete the account. Why wouldnt it work?
    – Amax1
    Commented May 20, 2022 at 8:40
  • To do the account.Contacts is a relationship SOQL Query mandatory?
    – Amax1
    Commented May 20, 2022 at 9:17
  • Yes, if you query Contacts from Account [SELECT Id, (SELECT LastName FROM Contacts) FROM Account WHERE Id IN : Trigger.oldMap.keySet()] then you will be able to use account.Contacts.size(). By default you do not have an access in triggers to Contacts (and to other relations as well). That is why you need to query that fields and then you can relate to them in your code Commented May 20, 2022 at 9:29
  • Thanks a lot Kate !!. Really cleared the concepts along with getting the right answer !! :D
    – Amax1
    Commented May 20, 2022 at 9:36
0

How are you getting the Contacts??

Basically, your code is getting nothing when you say acc.Contacts.

Try debugging it in the System debug and check what is the value in your acc.Contacts.

trigger AccountDeleteonPrevention on Account (before delete) {
    
    if(Trigger.isBefore && Trigger.isDelete){
           for(Account acc: Trigger.old){
             System.debug('## Account>Contacts --> '+  acc.Contacts); // According to me This is not list of contacts and that's the issue here.
             if(acc.Contacts.size()>0){
                   acc.addError('You cannot delete this account');
                   
               }          
       
    }
        
    }
   
}

Solution: I think you should create a field to maintain the Contact record count on the Account and then add that field to your condition.

1
  • Its coming as blank. Just blank paranthesis. Actualy I got the Contacts from this online example where we use SOQL Query List<Account> acc=[select Name , (Select LastName from Contacts) from Account Limit 10]; for(Account acct:acc){ system.debug('####'+acct.Contacts.size()); } Is it possible directly without creating a field?
    – Amax1
    Commented May 20, 2022 at 8:25
0
trigger preventAccountDeletion on Account (before delete) {
    // Check if the trigger is before delete
    if (Trigger.isBefore && Trigger.isDelete) {
        // Query for account IDs that have related contacts
        List<AggregateResult> accountWithContact = [
            SELECT AccountId
            FROM Contact
            WHERE AccountId IN :Trigger.oldMap.keySet()
            GROUP BY AccountId
            HAVING COUNT(Id) > 0
        ];

        // Throw an error if there are accounts with related contacts
        if (accountWithContact.size() > 0) {
            Trigger.old[0].addError(accountWithContact.size() + ' Accounts cannot be deleted because they have related contacts.');
        }
    }
}
8
  • I've fixed the code formatting for you, but some additional explanation would be good.
    – Derek F
    Commented Nov 9 at 13:32
  • This approach wouldn't play well with allOrNone=false dml operations since it only adds the error to the first record instead of adding errors based on the AccountId(s) returned by the query.
    – Derek F
    Commented Nov 9 at 13:34
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Nov 9 at 16:41
  • for (Account acc : (accountIdsWithContacts) { acc.addError('This account cannot be deleted because it has related contacts.'); // Throw a custom exception to stop the transaction entirely //throw new CustomException('Account deletion prevented due to related contacts.'); } Commented Nov 10 at 14:51
  • when you use addError in a before delete trigger, Salesforce prevents the deletion of any records in the transaction. Here’s what happens in detail: 1. Error Handling with addError: When addError is called on any record within the Trigger.old list, it stops the entire deletion operation and rolls back changes for all records in the transaction. Salesforce treats the error as a failure of the entire DML operation, not just for the specific record. Commented Nov 10 at 14:56
-2

Maybe u can try this as well

trigger demoAcct on Account (before delete) {
    for(Account ac:trigger.old){
        List<Contact> relatedConList = [Select AccountId from Contact Where AccountId=: ac.Id];
        if(relatedConList.size()>0){
            ac.addError('You cannot delete this account');
        }
    }
}
1
  • 2
    You are using SOQL Query inside a for loop. This is considered bad practice as it hits governor limits.
    – Amax1
    Commented Oct 6, 2022 at 11:27

You must log in to answer this question.

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