function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MrBrianMrBrian 

Activate trigger when relationship is removed?

Hi everyone,

I have a trigger on the Event Object that basically serves as a rollup summary to count the number of certain types of Events that are related to an account, and then display that number on the parent Account. The code seems to work really well, except for when the whatId relationship is changed or removed on the event.

For example, if I have a single Event A where the whatId is Account A, it properly shows on the Account A record that there is 1 child event. However, if I change the whatId relationship to Account B, Account A will not get updated by the trigger on the event, and will still show (falsely) that there is 1 child event on the account.

I believe that I need to add a case for my code using the trigger.old value for the event, however I could really use some guidence on how exactly to account for this case. Here is my current code.
 
/* Provide summary of Number of Site Visit Events on Account record and populates the Site Visit Date field*/

trigger countSiteVisits on Event (after delete, after insert, after undelete, 
after update) {

    Event[] events;
    if (Trigger.isDelete) 
        events = Trigger.old;
    else
        events = Trigger.new;

    // get list of accounts
    Set<ID> acctIds = new Set<ID>();
    for (Event evn : events) {
            acctIds.add(evn.WhatId);
    }
    
    Map<ID, Event> eventsForAccounts = new Map<ID, Event>([select Id
                                                            ,WhatId
                                                            from Event
                                                            where WhatId in :acctIds AND Type ='Site Visit' AND GTM_Status__c = 'Completed' AND isDeleted = FALSE ALL ROWS]);

    Map<ID, Account> acctsToUpdate = new Map<ID, Account>([select Id
                                                                 ,Completed_Site_Visits__c
                                                                  from Account
                                                                  where Id in :acctIds]);
    
    for (Account acct : acctsToUpdate.values()) {
        Set<ID> eventIds = new Set<ID>();
        
        for (Event evn : eventsForAccounts.values()) {
            if (evn.WhatId == acct.Id)
            eventIds.add(evn.Id);
        }
              
        if (acct.Completed_Site_Visits__c != eventIds.size())
            acct.Completed_Site_Visits__c = eventIds.size();
            
        Map<ID, Event> latestEventForAccount = new Map<ID, Event>([SELECT Id, ActivityDate FROM Event
                                                                    WHERE WhatId = :acct.Id AND ID in :eventIds AND Type ='Site Visit' AND GTM_Status__c = 'Completed' AND isDeleted = FALSE ORDER BY ActivityDate DESC LIMIT 1 ALL ROWS]);
        
        for (Event mylatestEvent: latestEventForAccount.values()) {
            if (mylatestEvent.ActivityDate != null)
            acct.Site_Visit_Date__c = mylatestEvent.ActivityDate;
        }
    }

    try {
        update acctsToUpdate.values();
    }
    
    catch (DMLException e) {
        for (event eventCatch: trigger.new) {
            eventCatch.addError(e.getDmlMessage(0));
        }
    }
    catch (Exception e) {
        for (event eventCatch : trigger.new) {
            eventCatch.addError(e.getMessage());
        }
    }
}
Any help appreciated, thank you!
 
Kevin CrossKevin Cross
You are correct.  Inside your loop of events, you could use Trigger.isUpdate to determine when you have a potential old WhatId.  In this if condition, you then can use Trigger.oldMap.get(evn.Id) to retrieve the old version of the event.  If the old WhatId is different, add it to the list to get updated as well.

I hope that helps!
MrBrianMrBrian
Much appreciated. In case anyone else needs to fix this issue for counting child records and recording the value to the parent object, here is my revised code (updated lines 16-17, and in my case, lines 53-55 to record (or remove)) the last activity's date:
 
/* Provide summary of Number of Site Visit Events on Account record and populates the Site Visit Date field*/

trigger countSiteVisits on Event (after delete, after insert, after undelete, 
after update) {

    Event[] events;
    if (Trigger.isDelete) 
        events = Trigger.old;
    else
        events = Trigger.new;

    // get list of accounts
    Set<ID> acctIds = new Set<ID>();
    for (Event evn : events) {
            acctIds.add(evn.WhatId);
            if (Trigger.isUpdate && Trigger.oldMap.get(evn.Id).WhatId != evn.WhatId) {
                acctIds.add(Trigger.oldMap.get(evn.Id).WhatId);
            }
                
    }
    
    Map<ID, Event> eventsForAccounts = new Map<ID, Event>([select Id
                                                            ,WhatId
                                                            from Event
                                                            where WhatId in :acctIds AND Type ='Site Visit' AND GTM_Status__c = 'Completed' AND isDeleted = FALSE ALL ROWS]);

    Map<ID, Account> acctsToUpdate = new Map<ID, Account>([select Id
                                                                 ,Completed_Site_Visits__c
                                                                  from Account
                                                                  where Id in :acctIds]);
    
    
    for (Account acct : acctsToUpdate.values()) {
        Set<ID> eventIds = new Set<ID>();
        //Set oldEventIds
        
        for (Event evn : eventsForAccounts.values()) {
            if (evn.WhatId == acct.Id)
            eventIds.add(evn.Id);
        }
              
        if (acct.Completed_Site_Visits__c != eventIds.size())
            acct.Completed_Site_Visits__c = eventIds.size();
            
        Map<ID, Event> latestEventForAccount = new Map<ID, Event>([SELECT Id, ActivityDate FROM Event
                                                                    WHERE WhatId = :acct.Id AND ID in :eventIds AND Type ='Site Visit' AND GTM_Status__c = 'Completed' AND isDeleted = FALSE ORDER BY ActivityDate DESC LIMIT 1 ALL ROWS]);
        
        for (Event mylatestEvent: latestEventForAccount.values()) {
            if (mylatestEvent.ActivityDate != null){
                   acct.Site_Visit_Date__c = mylatestEvent.ActivityDate;
            }
        }
        if(latestEventForAccount.size() == 0){
                acct.Site_Visit_Date__c = null;
            }

    }

    try {
        update acctsToUpdate.values();
    }
    
    catch (DMLException e) {
        for (event eventCatch: trigger.new) {
            eventCatch.addError(e.getDmlMessage(0));
        }
    }
    catch (Exception e) {
        for (event eventCatch : trigger.new) {
            eventCatch.addError(e.getMessage());
        }
    }
}

 
Kevin CrossKevin Cross
I am glad my comment helped you revise code and think the community will be appreciative that you posted the final query here.  Thanks for sharing!  Good luck and happy coding, Kevin.