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
Brian Nolau 2Brian Nolau 2 

Question on complex APEX code that shows how to run after insert and after update triggers?

So i'm about 50% into my Learning Salesforce Development with Apex: Write, Run and Deploy Apex Code with Ease (English Edition) book and I'm stuck on the below code. I provide a text version under the image. The below code has no problems. When I create a new task nothing happens though and if I create a task with a Contact it has an issue that says: TaskTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.TaskTrigger: line 14, column 1

User-added imageText version of the code from Learning Salesforce Development with Apex: Write, Run and Deploy Apex Code with Ease (English Edition):

trigger TaskTrigger on Task (after insert, after update) {
    switch on Trigger.operationType {
        when AFTER_INSERT {
        Set<Id> contactIds = new Set<Id>();
    For(Task t: Trigger.new) {
    If(t.WhoId != null && String.valueOf(t.WhoId).startsWith('003')) {
    contactIds.add(t.WhoId);
    }
    }
    Map<Id, Contact> contactMap = new Map<Id, Contact> ([SELECT Id, No_Of_Open_Tasks__c FROM Contact WHERE Id in: contactIds]);

    For(Task t :Trigger.new) {
    If(contactMap.containsKey(t.WhoId)) {
    contactMap.get(t.WhoId).No_of_Open_Tasks__c += 1;
    }
    }
    Update contactMap.values();
    }
        when AFTER_UPDATE {            
        Set<ID> contactIds = new Set<Id>();
    For(Task t : Trigger.new) {
    If(t.IsClosed && !Trigger.oldMap.get(t.Id).IsClosed && t.WhoId != null && String.valueOf(t.WhoId).startsWith('003')) {
    contactIds.add(t.WhoId);
    }
    }
    Map<Id, Contact> contactMap = new Map<Id, Contact>([SELECT Id, No_Of_Open_Tasks__c FROM Contact WHERE Id in :contactIds]);

    For(Contact con : contactMap.values()) {
    Con.No_of_open_tasks__c = 0;
    }

    For(AggregateResult ar : [SELECT WhoId, Count(Id) total FROM Task WHERE IsClosed = false AND WhoId in :contactIds GROUP BY WhoID]) {
    String who = String.Valueof(ar.get('WhoId'));
    Decimal total = (Decimal)(ar.get('total'));
    contactMap.get(who).No_of_Open_Tasks__c = total;
    }
    update contactMap.values();
        }
        }
}
Brian Nolau 2Brian Nolau 2
you can remove the last } and paste the below into an APEX Trigger called TaskTrigger  on a Task Object after creating a column called No_of_Open_Tasks__ in your Contacts object:


trigger TaskTrigger on Task (after insert, after update) {
    switch on Trigger.operationType {
        when AFTER_INSERT {
        Set<Id> contactIds = new Set<Id>();
    For(Task t: Trigger.new) {
    If(t.WhoId != null && String.valueOf(t.WhoId).startsWith('003')) {
    contactIds.add(t.WhoId);
    }
    }
    Map<Id, Contact> contactMap = new Map<Id, Contact> ([SELECT Id, No_Of_Open_Tasks__c FROM Contact WHERE Id in: contactIds]);

    For(Task t :Trigger.new) {
    If(contactMap.containsKey(t.WhoId)) {
    contactMap.get(t.WhoId).No_of_Open_Tasks__c += 1;
    }
    }
    Update contactMap.values();
    }
        when AFTER_UPDATE {            
        Set<ID> contactIds = new Set<Id>();
    For(Task t : Trigger.new) {
    If(t.IsClosed && !Trigger.oldMap.get(t.Id).IsClosed && t.WhoId != null && String.valueOf(t.WhoId).startsWith('003')) {
    contactIds.add(t.WhoId);
    }
    }
    Map<Id, Contact> contactMap = new Map<Id, Contact>([SELECT Id, No_Of_Open_Tasks__c FROM Contact WHERE Id in :contactIds]);

    For(Contact con : contactMap.values()) {
    Con.No_of_open_tasks__c = 0;
    }

    For(AggregateResult ar : [SELECT WhoId, Count(Id) total FROM Task WHERE IsClosed = false AND WhoId in :contactIds GROUP BY WhoID]) {
    String who = String.Valueof(ar.get('WhoId'));
    Decimal total = (Decimal)(ar.get('total'));
    contactMap.get(who).No_of_Open_Tasks__c = total;
    }
    update contactMap.values();
        }
        }
Brian Nolau 2Brian Nolau 2
nervermind it works:
User-added image
does anyone have an APEX book that they recommend I hate reading a book and the author goes insane with power 100 pages in
JaimeBidJaimeBid

Hi Brian, how did you manage to solve it? I am on the same page of the book right now... same error:

TaskTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.TaskTrigger: line 25, column 1

I populate the "No of open task" field using a List instead of a Map but as the writer explains, this only works if you insert one task per contact

I will keep on trying

 

JaimeBidJaimeBid

Hi Brian, I think the default value of 0 is missing, that is the reason for the error to show up
I tried setting up the value of "No_Of_Open_Tasks__c" to 0 and then it works

To clarify (for anyone reaching this matter), this would not work:
Integer tasks;
tasks += 1;
As "tasks" is stated as null:

But this would:
Integer tasks = 0;
tasks += 1;
system.debug(tasks);

Took me a while to find it out, I am learning APEX too 😉

Have a nice weekend