Why does my after-delete trigger fail?

Spread the love

Question

I’m encountering an issue with the following trigger method. When attempting to delete an employee record (via UI), the operation fails, and I get this error:

“There’s a problem saving this record. You might not have permission to edit it, or it might have been deleted or archived.”

Here is my trigger:

trigger EmployeeTrigger on Employee__c (before delete, after delete) {   
    if (Trigger.isAfter && Trigger.isDelete)
        EmployeeTriggerHandler.afterDelete(Trigger.old);
}  

The trigger calls this method in the handler:

public class EmployeeTriggerHandler {
    
    // After employee is deleted, update 'Left Employee Count' on Account
    public static void afterDelete(List<Employee__c> oldList){
        List<Account> accToUpdate = new List<Account>();
        for (Employee__c e : oldList){
            if (e.Account__c != null){
                e.Account__r.Left_Employee_Count__c = [SELECT count() FROM Employee__c WHERE Account__c =: e.Account__c];
                accToUpdate.add(e.Account__r);
            }
        }
        update accToUpdate;
    }
}

Observed Behavior:

  • The employee record fails to delete.
  • The operation ends with the mentioned error.

Can you help me figure out what is causing this issue and how to resolve it?

Answer

The issue with your code is that you are attempting to update Account records using the Account__r relationship field directly, but you did not fetch the Id for these Account records. Salesforce requires the Id field to perform DML operations like update. Without the Id, the platform cannot determine which Account records to update, resulting in the error you encountered.

Resolution

You need to modify your afterDelete method to properly query the Account records and ensure they include the required Id field before attempting the update. Below is the corrected version of your handler method:

public class EmployeeTriggerHandler {    
    public static void afterDelete(List<Employee__c> oldList) {
        // Accounts to update, deduplicated by Id
        Map<Id, Account> accounts = new Map<Id, Account>();
        // Record counts
        Map<Id, AggregateResult> recordCounts = new Map<Id, AggregateResult>();
        
        // Aggregate the Account Id values
        for (Employee__c record : oldList) {
            if (record.Account__c != null) {
                accounts.put(record.Account__c, new Account(Id = record.Account__c));
            }
        }

        // Get the record counts all at once
        recordCounts.putAll([
            SELECT Account__c Id, COUNT(Id) recordCount 
            FROM Employee__c 
            WHERE Account__c IN :accounts.keySet() 
            GROUP BY Account__c
        ]);

        // Update the Left_Employee_Count__c for each Account
        for (Account account : accounts.values()) {
            account.Left_Employee_Count__c = (Integer) recordCounts.get(account.Id)?.get('recordCount') ?? 0;
        }

        // Update the Account records
        update accounts.values();
    }
}

Explanation

This solution ensures that you are working with the Id field for each Account. The recordCounts map aggregates the number of Employee__c records linked to each Account, grouped by Account__c. It uses the Safe Navigation Operator (?.) and Null Coalescing Operator (??) to avoid null pointer exceptions and provides default values when no matching records exist. This method is efficient and avoids errors related to invalid or missing Id fields.

Alternative Approach

If you want to avoid querying Account records separately and instead calculate the employee count on-the-fly, you can use the following simplified method:

public class EmployeeTriggerHandler {    
    public static void afterDelete(List<Employee__c> oldList) {
        Map<Id, Integer> employeeCounts = new Map<Id, Integer>();

        // Calculate counts dynamically
        for (Employee__c record : oldList) {
            if (record.Account__c != null) {
                employeeCounts.put(record.Account__c, 
                    employeeCounts.getOrDefault(record.Account__c, 0) + 1);
            }
        }

        List<Account> accountsToUpdate = new List<Account>();
        for (Id accountId : employeeCounts.keySet()) {
            accountsToUpdate.add(new Account(
                Id = accountId, 
                Left_Employee_Count__c = employeeCounts.get(accountId)
            ));
        }

        update accountsToUpdate;
    }
}

This approach reduces the number of SOQL queries by counting employee records in Apex itself. However, it may not scale well for a large dataset due to governor limits. For optimal performance, the first approach with SOQL aggregation is recommended.

By using either method, you ensure that the Account records are properly updated, and the error is resolved.

Real-Time Project-Based Salesforce Training to Kick Start Your Career

Our Salesforce Course provides a thorough understanding of the Salesforce platform, equipping you with the essential skills to excel in the competitive CRM industry. The program focuses on key areas such as Salesforce Admin, Developer, and AI, blending theoretical knowledge with hands-on practical training. Through live projects and assignments, you’ll gain real-world experience and the confidence to tackle complex business challenges using Salesforce solutions. Guided by expert instructors, you’ll develop the technical skills and industry expertise necessary to thrive in the Salesforce environment.

In addition to technical training, our Salesforce training in India offers personalized mentorship, certification exam preparation, and interview coaching to give you a professional edge. You’ll benefit from detailed study resources, hands-on project experience, and dedicated support throughout your learning journey. Upon completing the course, you’ll be fully prepared for certification exams and equipped with the problem-solving skills employers value most. Embark on your Salesforce journey with us today and unlock unlimited career opportunities.  Enroll for a Free Demo today!

Open Chat
1
Dear Sir/Madam
How can I help you?