0

i have some issues with some Lead or Contact records (this method is Contact one) i have a Trigger in before update just passing a List of contact with some criteria got from Trigger.New. This list is the parameter for this method running in the trigger i have "Attempt to De-Reference a Null Object - line 88" on some Contact record (i can't figure what criteria is giving this error)


public static void recalculateContactSigns(List<Contact> contacts)
    {
        List<Sign__c> signs = [SELECT Id, Contact__c,Petition__c, Sign_date__c FROM Sign__c WHERE Contact__c IN :contacts];

        if(!signs.isEmpty())
        {
            Map<Contact,List<Sign__c>> contact_perSigns = new Map<Contact,List<Sign__c>>();

            for(Contact c : contacts)
            {
                List<Sign__c> thisContactSignsList = new List<Sign__c>();
                for(Sign__c s : signs)
                {
                    if(s.Contact__c == c.Id)
                    {
                        thisContactSignsList.add(s);
                    }
                }
                contact_perSigns.put(c, thisContactSignsList);
            }

            for(Contact c : contacts)
            {
                System.debug('## LIST: ' + contact_perSigns.get(c));
                System.debug('## SIZE: ' + contact_perSigns.get(c).size());
                c.Petitions_Signatures_number__c = contact_perSigns.get(c).size();
               
                **//88 ERROR LINE** if(!contact_perSigns.get(c).isEmpty() || contact_perSigns.get(c) != null) 
                {
                    if(contact_perSigns.get(c).size() > 1)
                    {
                        Sign__c latestSign = getLatestSignFromList(contact_perSigns.get(c));
                        c.Last_Date_Petition_Signed__c = latestSign.Sign_date__c;
                        c.Petition__c = latestSign.Petition__c;
                    }
                    else
                    {
                        Sign__c latestSign = contact_perSigns.get(c)[0];
                        c.Last_Date_Petition_Signed__c = latestSign.Sign_date__c;
                        c.Petition__c = latestSign.Petition__c;
                    }

                }
                else{System.debug('## ELSE STATEMENT: NO SIGNS, SKIP..') ;}
                
            }
        }
        else return;

    }
1
  • You are using contact as the key of the map that is the problem, use the contact id instead. Aug 26, 2020 at 10:21

2 Answers 2

2

The issue

The main issue here is that you've chosen to use an SObject (more specifically, Contact) as the key of a map.

While it's certainly possible to do that, it's not recommended in most cases.

Map keys are hashed, and SObjects happen to be one of the things that get stored in collections (maps, sets, and lists) by reference. When you run line 86

c.Petitions_Signatures_number__c = contact_perSigns.get(c).size();

you're also inadvertently changing the map key, and that ends up making the data in your map inaccessible.

Fixing it

You can fix it by using the more common approach of using an Id as the key of your map, making it a Map<Id, List<Sign__c>> rather than a Map<Contact, List<Sign__c>>. In this case, the Id in question would be the Contact's Id.

Bonus

You also have the following construct in your code

for(object 1){
    for(object 2){
        if(object1.Field == object2.Field){
            // do some work
        }
    }
}

That ends up being somewhat wasteful. In this particular case, your Sign__c records already have the Contact Id that they should be put under, so there is no need for the nested loop here.

A better approach would be to just build your map by iterating over your Sign__c records.

for(Sign__c sign :signs){
    // first thing, check to see if the map already has the current Contact Id as
    //   a key
    if(!myMap.containsKey(sign.Contact__c)){
        // in here, the map does not yet contain the key
        // let's add the key to the map
        // This also allows us the chance to initialize the value stored by the given key
        //  (which is important here, since we're working with a List rather than
        //  a primitive value like an Integer, Bool, String, etc...)
        myMap.put(sign.Contact__c, new List<Sign__c>());
    }

    // Now, at this point, we're guaranteed to have the map contain our key
    // Simply add to the stored list
    myMap.get(sign.Contact__c).add(sign);
}

That's much improved, but this is a case where we can do better still.

Provided that Sign.Contact__c is a relationship field (lookup or master-detail), and seeing how you already need to perform a query to get Sign__c records anyway, you can basically eliminate all this work by using a parent-child subquery.

Map<Id, Contact> contactMapWithSigns = new Map<Id, Contact>([SELECT Id, (SELECT d, Contact__c,Petition__c, Sign_date__c FROM Signs__r ORDER BY CreatedDate DESC) FROM Contact WHERE Id IN :contacts]);

When using a subquery like this, instead of __c, you use the child relationship name. In most cases for custom relationships, that simply means use the plural and end it with __r instead of __c.

That gives you a List<Sign__c> embedded within each Contact.

Using it would look something like this

for(Contact c :contactsPassedIn){
    c.Signature_Count__c = contactMapWithSigns.get(c.Id).Signs__r.size();

    if(c.Signature_Count__c > 0){
        Sign__c mostRecent = contactMapWithSigns.get(c.Id).Signs__r[0];
        // ...other code
    }
}
1
  • this worked like a charme thank you very much
    – user87699
    Aug 26, 2020 at 11:45
0

As Rahul mentioned you need to change your key from Contact to Contact Id. See the updated code

public static void recalculateContactSigns(List<Contact> contacts)
    {
        List<Sign__c> signs = [SELECT Id, Contact__c,Petition__c, Sign_date__c FROM Sign__c WHERE Contact__c IN :contacts];

        if(!signs.isEmpty())
        {
            Map<Id,List<Sign__c>> contact_perSigns = new Map<Id,List<Sign__c>>();

            for(Contact c : contacts)
            {
                List<Sign__c> thisContactSignsList = new List<Sign__c>();
                for(Sign__c s : signs)
                {
                    if(s.Contact__c == c.Id)
                    {
                        thisContactSignsList.add(s);
                    }
                }
                contact_perSigns.put(c.Id, thisContactSignsList);
            }

            for(Contact c : contacts)
            {
                System.debug('## LIST: ' + contact_perSigns.get(c.Id));
                System.debug('## SIZE: ' + contact_perSigns.get(c.Id).size());
                c.Petitions_Signatures_number__c = contact_perSigns.get(c.Id).size();
               
                **//88 ERROR LINE** if(!contact_perSigns.get(c).isEmpty() || contact_perSigns.get(c) != null) 
                {
                    if(contact_perSigns.get(c.Id).size() > 1)
                    {
                        Sign__c latestSign = getLatestSignFromList(contact_perSigns.get(c.Id));
                        c.Last_Date_Petition_Signed__c = latestSign.Sign_date__c;
                        c.Petition__c = latestSign.Petition__c;
                    }
                    else
                    {
                        Sign__c latestSign = contact_perSigns.get(c.Id)[0];
                        c.Last_Date_Petition_Signed__c = latestSign.Sign_date__c;
                        c.Petition__c = latestSign.Petition__c;
                    }

                }
                else{System.debug('## ELSE STATEMENT: NO SIGNS, SKIP..') ;}
                
            }
        }
        else return;

    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.