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
cloudboom.phcloudboom.ph 

Bulk Trigger Null Pointer Help

Hi all,

I am trying to develop a trigger, but it seems I keep hitting a Null Pointer Exception and cannot figure out why.  Anyone can help take a look?

 

trigger AccountChildRollup2 on account (before update, before insert) {
    set<id> pid = new set<id>();
    for (account child : trigger.new){
        pid.add(child.parent.id);
    }
    aggregateresult children = [select count(id) from account where parentid in: pid];
    aggregateresult livechildren = [select count(id) from account where type = 'Live' and parentid in: pid];
    integer childcount = integer.valueof(children.get('expr0'));
    integer livechildcount = integer.valueof(livechildren.get('expr0'));
    
    map<id,account> pmap = new map<id,account>([select id, type, go_live_date__c, count_child_accounts__c, count_live_child_accounts__c from account where id in: pid]);
    
    for (account child : trigger.new){
        account p = pmap.get(child.parentid);
        p.count_child_accounts__c = childcount;
        p.count_live_child_accounts__c = livechildcount;
        pmap.put(p.id,p);
    }
    update pmap.values();

}

Error:Apex trigger AccountChildRollup2 caused an unexpected exception, contact your administrator: AccountChildRollup2: execution of BeforeUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AccountChildRollup2: line 15, column 1 

Best Answer chosen by Admin (Salesforce Developers) 
vishal@forcevishal@force

I guess it might be because some Account has no parent.

 

Anyway, give this a try and let me know:

 

for (account child : trigger.new){
     system.debug('Parent ID ' + child.parentid);
     if(child.parentid != null && pmap.containsKey(child.parentid))
     {
          account p = pmap.get(child.parentid);
          p.count_child_accounts__c = childcount;
          p.count_live_child_accounts__c = livechildcount;
          system.debug('test ' + p.id);
          pmap.put(p.id,p);
     }
}
if(pmap != null)
     update pmap.values();

All Answers

kirkevonphillykirkevonphilly

Is your pid set populating?  

 

What if you change this line:

 pid.add(child.parent.id);

to this (remove the dot):

 pid.add(child.parentid);

 

Just had a scenario where the dot version was coming back null, resulting in an empty set, causing issues further down the line.  

 

Add some system.debugs to see if in the logs

for (account child : trigger.new){
        system.debug('Without dot:  ' + child.parentid);
system.debug('With dot: ' + child.parent.id);
pid.add(child.parent.id); }
vishal@forcevishal@force

Yes, that should be the issue.

 

The reason for that is in your trigger.new, you only have access to fields on the object your trigger is written upon and not on the related objects. To get the related object's data, you need to query them.

 

So, if I have a trigger on Contact

 

for(Contact c : trigger.new)

{

     system.debug('=== I can see this === ' + c.AccountId); // because this is a field on Contact, I can access it

     system.debug('=== I get null here === ' + c.Account.Name'); // or any other field on Account can't be accessed. You need to query.

}

cloudboom.phcloudboom.ph

Hi Vishal,

Thanks and looks like it helped on my first for statement.  But now on my second for statement, I am getting null values for the same request for the Parent ID...why is this now happening?

 

trigger AccountChildRollup2 on account (before update, before insert) {
    set<id> pid = new set<id>();
    for (account child : trigger.new){
        system.debug('Parent ID '+ child.parentid);
        pid.add(child.parentid);
    }
    aggregateresult children = [select count(id) from account where parentid in: pid];
    aggregateresult livechildren = [select count(id) from account where type = 'Live' and parentid in: pid];
    integer childcount = integer.valueof(children.get('expr0'));
    integer livechildcount = integer.valueof(livechildren.get('expr0'));
    
    map<id,account> pmap = new map<id,account>([select id, type, go_live_date__c, count_child_accounts__c, count_live_child_accounts__c from account where id in: pid]);
    
    for (account child : trigger.new){
        system.debug('Parent ID ' + child.parentid);
        account p = pmap.get(child.parentid);
        p.count_child_accounts__c = childcount;
        p.count_live_child_accounts__c = livechildcount;
        system.debug('test ' + p.id);
        pmap.put(p.id,p);
    }
    update pmap.values();

}

 Error:Apex trigger AccountChildRollup2 caused an unexpected exception, contact your administrator: AccountChildRollup2: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 001R000000l3E2yIAE; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountChildRollup2: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.AccountChildRollup2: line 17, column 1: []: Trigger.AccountChildRollup2: line 22, column 1

vishal@forcevishal@force

I guess it might be because some Account has no parent.

 

Anyway, give this a try and let me know:

 

for (account child : trigger.new){
     system.debug('Parent ID ' + child.parentid);
     if(child.parentid != null && pmap.containsKey(child.parentid))
     {
          account p = pmap.get(child.parentid);
          p.count_child_accounts__c = childcount;
          p.count_live_child_accounts__c = livechildcount;
          system.debug('test ' + p.id);
          pmap.put(p.id,p);
     }
}
if(pmap != null)
     update pmap.values();

This was selected as the best answer
cloudboom.phcloudboom.ph

Hey Vishal,

This is working well!  But now, whenever I do a batch update, my aggregate results are way off of the actual aggregate result.  I get the right values when I edit the accounts individually, but when I do a batch update, the counts are way too high.  Here is my current trigger:

trigger AccountChildRollup2 on account (after update, after insert, after delete) {
    set<id> pid = new set<id>();
    list<account> childupdate = new list<account>();
    if (trigger.isinsert || trigger.isupdate){
        for (account a : trigger.new){
            pid.add(a.parentid);
        }
    }
    if (trigger.isdelete){
        for (account a : trigger.old){
            pid.add(a.parentid);
        }
    }
    aggregateresult children = [select count(id) from account where parentid != null and parentid in: pid];
    aggregateresult livechildren = [select count(id) from account where type = 'Live' and parentid in: pid];
    aggregateresult golivedate = [select min(go_live_date__c) from account where go_live_date__c != null and type = 'Live' and parentid in: pid];
    integer childcount = integer.valueof(children.get('expr0'));
    integer livechildcount = integer.valueof(livechildren.get('expr0'));
    date mingolivedate = date.valueof(golivedate.get('expr0'));
    
    map<id,account> pmap = new map<id,account>([select id, type, go_live_date__c, count_child_accounts__c, count_live_child_accounts__c from account where id in: pid]);
    
    if (trigger.isinsert || trigger.isupdate){
        for (account a : trigger.new){
            if (childcount > 0 && a.parentid != null && pmap.containsKey(a.parentid)){
                account p = pmap.get(a.parentid);
                p.count_child_accounts__c = childcount;
                p.count_live_child_accounts__c = livechildcount;
                p.this_is_a_parent_account__c = true;
                if (livechildcount > 0 && pmap.containsKey(a.parentid)){
                    p.type = 'Live';
                    p.go_live_date__c = mingolivedate;
                }
                p.validation_override__c = datetime.now();
                p.button_validate__c = datetime.now();
                pmap.put(p.id,p);
            }
        }
    }
    if (trigger.isdelete){
        for (account a : trigger.old){
            if (a.parentid != null && pmap.containsKey(a.parentid)){
                account p = pmap.get(a.parentid);
                p.count_child_accounts__c = childcount;
                p.count_live_child_accounts__c = livechildcount;
                p.this_is_a_parent_account__c = true;
                if (livechildcount > 0 && pmap.containsKey(a.parentid)){
                    p.type = 'Live';
                    p.go_live_date__c = mingolivedate;
                }
                p.validation_override__c = datetime.now();
                p.button_validate__c = datetime.now();
                pmap.put(p.id,p);
            }
        }
    }
    if(pmap != null)
    update pmap.values();
}

 

vishal@forcevishal@force

That is because in batch updates, you'll be querying results based on Parent records of all the updated Accounts. Here, you'll have to use a GROUP BY clause where in you should be Grouping the results by ParentId. This will give you results for each Parent record instead of the one whole result-set for all Parents.

cloudboom.phcloudboom.ph

Thanks again Vishal, but now when I have an aggregate result that returns null values (where no records meet the criteria), I get an error:  

 

"Error:Apex trigger AccountChildRollup2 caused an unexpected exception, contact your administrator: AccountChildRollup2: execution of AfterUpdate caused by: System.QueryException: List has no rows for assignment to SObject: Trigger.AccountChildRollup2: line 17, column 1"

 

Also, is there a more efficient way to doo the aggregate result?   I get really close to the query row limits with this:

 

trigger AccountChildRollup2 on account (after update, after insert, after delete) {
    set<id> pid = new set<id>();
    list<account> childupdate = new list<account>();
    integer childcount2;
    if (trigger.isinsert || trigger.isupdate){
        for (account a : trigger.new){
            pid.add(a.parentid);
        }
    }
    if (trigger.isdelete){
        for (account a : trigger.old){
            pid.add(a.parentid);
        }
    }
    
    aggregateresult children = [select count(id) childcount from account where parentid != null and parentid in: pid group by parentid];
    aggregateresult livechildren = [select count(id) from account where type = 'Live' and parentid in: pid group by parentid];
    aggregateresult golivedate = [select min(go_live_date__c) from account where go_live_date__c != null and type = 'Live' and parentid in: pid];
    integer childcount = integer.valueof(children.get('childcount'));
    integer livechildcount = integer.valueof(livechildren.get('expr0'));
    date mingolivedate = date.valueof(golivedate.get('expr0'));
    
    map<id,account> pmap = new map<id,account>([select id, type, go_live_date__c, count_child_accounts__c, count_live_child_accounts__c from account where id in: pid]);
    
    if (trigger.isinsert || trigger.isupdate){
        for (account a : trigger.new){
            if (childcount > 0 && a.parentid != null && pmap.containsKey(a.parentid)){
                account p = pmap.get(a.parentid);     
                p.count_child_accounts__c = childcount;
                p.count_live_child_accounts__c = livechildcount;
                if (p.parentid == null){
                    p.this_is_a_parent_account__c = true;
                }
                if (livechildcount > 0 && pmap.containsKey(a.parentid)){
                    p.type = 'Live';
                    p.go_live_date__c = mingolivedate;
                }
                p.validation_override__c = datetime.now();
                p.button_validate__c = datetime.now();
                pmap.put(p.id,p);
            }
        }
    }
    if (trigger.isdelete){
        for (account a : trigger.old){
            if (a.parentid != null && pmap.containsKey(a.parentid)){
                account p = pmap.get(a.parentid);
                p.count_child_accounts__c = childcount;
                p.count_live_child_accounts__c = livechildcount;
                if (p.parentid == null){
                    p.this_is_a_parent_account__c = true;
                }
                if (livechildcount > 0 && pmap.containsKey(a.parentid)){
                    p.type = 'Live';
                    p.go_live_date__c = mingolivedate;
                }
                p.validation_override__c = datetime.now();
                p.button_validate__c = datetime.now();
                pmap.put(p.id,p);
            }
        }
    }
    if(pmap != null)
    update pmap.values();
}