[SalesForce] Trigger to get fields from Object linked with the ‘Related To’ field in an Task

This is linked to this other Salesforce Stack Exchange question and answer: Trigger to get fields from Object linked with the 'Related To' field in an Event

I have a custom object called Customer_Statement__c. When I associate a task to a record of this sObject, a custom lookup (account) field on the task called 'Account_Name__c' should be populated with the Account__c value on the Customer_Statement__c field.

There is no compile error but when I create a task and have the task.type as 'Customer_Statement__c', the following error message is returned:

'execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AccountFromCustomerStatementOnTask: line 9, column 1'

I am confused about this error because the trigger puts the what.id in the Map as per line 7.

Any help would be much appreciated.

Many thanks,

trigger AccountFromCustomerStatementOnTask on Task (after insert, after update, before insert, before update) { 

    Map<Id, List<Task>> taskWhatIds = new Map<Id, List<Task>>{};

        for (Task t : trigger.new) {
            if (t.What.Type == 'Customer_Statement__c') {
                taskWhatIds.put(t.whatId, new List<Task>()); 
            }
                taskWhatIds.get(t.WhatId).add(t);
    }


    for (Customer_Statement__c cs: [Select Id, Account__c FROM Customer_Statement__c WHERE Id IN :taskWhatIds.keySet()]){
        for (task t : taskWhatIds.get(cs.id)){
            t.Account_Name__c = cs.Account__c;
        }
    }
}

TL;DR Objects in triggers can only get values from fields which are on the actual object itself. So I replaced t.what.type == 'abc' with String.valueOf(t.WhatId).startsWith('a00')) { //. This string method checks if the first 3 chars of the record Id correspond to the custom object id. More info here: What are Salesforce ID's composed of?

Best Answer

A common pattern for doing what I think you want is this:

        if (t.What.Type == 'Customer_Statement__c') {
            List<Task> tasks = taskWhatIds.get(t.WhatId);
            if (tasks == null) {
                tasks = new List<Task>();
                taskWhatIds.put(t.WhatId, tasks);
            }
            tasks.add(t); 
        }

where if there is already a list present in the map it is used else a list is added to the map. Then the object is added to the list. All of this has to be inside the if block.

PS But see Fernando's important point.