+ Start a Discussion
ilewi121ilewi121 

Parent-Child Update Trigger = Attempt to de-reference a null object

I have created two triggers, one on the Lead object, the other on a related custom object called 'LeadCompany__c.' When a lead is edited, it should update the related LeadCompany__c object, and when the LeadCompany__c object is updated, it should update all related leads.

My problem is that I am consistently running into the infamous "Attempt to de-reference a null object" error. For example, when I update the Lead "Company" field, it should update the LeadCompany__c.Name field, but it gives the following error: "Attempt to de-reference a null object Trigger.LD_Update_LC: line 82, column 1: []: Trigger.LC_Update_LD: line 93, column 1"

Here is the code for your review. Does anyone see how I can fix this?

//--------------------------------------------------------------------------------------------------------//
// LeadCompany__c Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LC_Update_LD on LeadCompany__c (before insert, before update, after update){

List<Lead> ldList = [SELECT Id, OwnerID, Company, LC_Lead_Company__c, Status, IsConverted FROM Lead WHERE LC_Lead_Company__C in :Trigger.new];
List<Lead> ldUpdate = new List<Lead>();
    List<Database.LeadConvert> leadConversions = new List<database.LeadConvert>();
LeadStatus convertStatus = [SELECT Id, MasterLabel, IsConverted FROM LeadStatus WHERE IsConverted=true limit 1];

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Updates Lead Count & Status
if(Trigger.isBefore){
  for (LeadCompany__c lc: Trigger.new){
   lc.Lead_Count__c = 0;
   Integer LC_Stat_Val = status_value.get(lc.Status__c);
   Integer LD_Stat_Vals = 0;
  
   for(Lead ld: ldList){
    if(ld.lc_Lead_Company__c == lc.Id){
     //Add to Lead Count
     Trigger.newMap.get(ld.LC_Lead_Company__c).Lead_Count__c++;
     //Compare Lead Status
     Integer LD_Stat_Value = status_value.get(ld.Status);
     if(LD_Stat_Value > LD_Stat_Vals){
      LD_Stat_Vals = LD_Stat_Value;
     }
    }
   }

   //Set Company Status
   if(LC_Stat_Val != LD_Stat_Vals){
    lc.Status__c = status_name.get(LD_Stat_Vals);
   }
  }
}

if(Trigger.isAfter){
  for (LeadCompany__c lc: Trigger.new) {
         LeadCompany__c oldLC = Trigger.oldMap.get(LC.ID);

            if(LC.Lead_Count__c != null){
    if(lc.ConvertedAccountId__c != null){
                   
                    for(Lead ld: LdList){
      if(ld.isConverted == False){
       Database.LeadConvert ldc = new Database.LeadConvert();
       ldc.setLeadId(ld.id);
       ldc.setAccountId(lc.ConvertedAccountId__c);
       ldc.setDoNotCreateOpportunity(TRUE);
                ldc.setConvertedStatus(convertStatus.MasterLabel);                   
       leadconversions.add(ldc);
      }
     }
    }

          if(LC.OwnerID != oldLC.OwnerID || LC.Name != oldLC.Name) {
              for(Lead ld: LdList){
            // Update Lead Owners
      if(ld.OwnerId != lc.OwnerId){
       ld.OwnerID = LC.OwnerID;
      }
            // Update Lead Company Names
      if(ld.Company != lc.Name){
                      ld.Company = LC.Name;
      }
      ldUpdate.add(ld);      
              }
          }
   }
  }
}

if(leadConversions.size()>0){
        List<Database.LeadConvertResult> results = Database.convertLead(leadConversions);
}
if(ldUpdate.size()>0){
  Update ldUpdate;
}
}

//--------------------------------------------------------------------------------------------------------//
// Lead Trigger
//--------------------------------------------------------------------------------------------------------//

trigger LD_Update_LC on Lead (before insert, before update, after delete, after insert, after update){

//Initialization
Map<Id, LeadCompany__c> updateCompanies = new Map<Id, LeadCompany__c>{};
List<Lead> associateLeads = new List<Lead>{};
List<Lead> convertLeads = new List<Lead>{};

List<Blacklist_Domain__c> Blacklist = [SELECT Name FROM Blacklist_Domain__c];
set<string> Blackset = new set<string>();
for (Blacklist_Domain__c bl: Blacklist){
  Blackset.add(bl.name);
}

Map<String, Integer> status_value = new Map<String, Integer>{
     'Open - Not Contacted' => 2,
     'Working - Contacted' => 3,
     'Working - Initial Meeting Scheduled' => 4,
     'Closed - Qualified' => 5,
     'Closed - Unqualified' =>1,
     null => 0
};

Map<Integer, String> status_name = new Map<Integer, String>{
     2 => 'Open - Not Contacted',
     3 => 'Working - Contacted',
     4 => 'Working - Initial Meeting Scheduled',
     5 => 'Closed - Qualified',
     1 => 'Closed - Unqualified',
     0 => null
};

//Start Trigger
if(Trigger.isBefore){

  //Isolate leads to associate
  if(Trigger.isInsert){
   for (Lead ld: Trigger.new){
    associateLeads.add(ld);
   }
  }
  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    Lead oldLd = Trigger.oldMap.get(ld.Id);
    if(oldLd.LC_Email_Domain__c != Ld.LC_Email_Domain__c){
     associateLeads.add(ld);
     if(oldLd.LC_Lead_Company__c != null){
      updateCompanies.put(oldLd.LC_Lead_Company__c, new LeadCompany__c(Id=oldLd.LC_Lead_Company__c));
     }
    }
   }
  }
}

if(Trigger.isAfter){

  //Update Company after Lead delete
  if(Trigger.isDelete){
   for (Lead ld: Trigger.old){
    if(ld.LC_Lead_Company__c != null){
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
   }
  }

  if(Trigger.isUpdate){
   for (Lead ld: Trigger.new){
    //Convert all Company leads
    if(Ld.IsConverted == True && ld.LC_Lead_Company__c != null){
     ld.LC_Lead_Company__r.ConvertedAccountId__c = ld.ConvertedAccountId;
     updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
    }
    //Check for Lead value changes
    else {
     Lead oldLd = Trigger.oldMap.get(Ld.ID);
     //Set LC OwnerId
     if(Ld.OwnerID != oldLd.OwnerID){
      ld.LC_Lead_Company__r.OwnerId = Ld.OwnerId;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Name
     if(Ld.Company != oldLd.Company){
      ld.LC_Lead_Company__r.Name = Ld.Company;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
     //Set LC Status
     if(Ld.Status != oldLd.Status){
      if(Ld.Status != Ld.LC_Status__c){
       Integer LC_Stat_Value = status_value.get(ld.LC_Lead_Company__r.Status__c);
       Integer LD_Stat_Value = status_value.get(ld.Status);

          if(LD_Stat_Value > LC_Stat_Value){
        ld.LC_Lead_Company__r.Status__c = status_name.get(LD_Stat_Value);
        updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
          }
      }
     }
    }
   }
  }
}

//Perform Updates

//Associate Leads to Companies
if(associateLeads.size()>0){
  for (Lead ld: associateLeads){
   //Validate Email
   if (ld.LC_Email_Domain__c != null && Blackset.contains(ld.LC_Email_Domain__c) == FALSE){
    //Search for existing company
    List<LeadCompany__c> lcMatch = [SELECT Id, OwnerId FROM LeadCompany__c WHERE Domain__c = :ld.LC_Email_Domain__c];
    // If existing, associate lead
    if (lcMatch.size() >0) {
     for( LeadCompany__c lc :lcMatch){
      // Associate Lead to Company
      ld.LC_Lead_Company__c = lc.Id;
      // Change Lead Owner to Company Owner
      ld.OwnerID = lc.ownerid;
      updateCompanies.put(lc.Id, new LeadCompany__C(Id=lc.Id));
     }
    }
    // If no existing, create new
    else {
     // Create new company
        LeadCompany__c nlc = new LeadCompany__c (
            Domain__c = ld.LC_Email_Domain__c,
            Name = ld.Company,
            OwnerId = ld.OwnerId,
            Status__c = ld.Status
        );
        insert nlc;

     // Associate new lead to new company
        ld.LC_Lead_Company__c = nlc.id;
     updateCompanies.put(nlc.Id, new LeadCompany__c(Id=nlc.Id));
    }
   }
   //Remove association
   else {
    ld.LC_Lead_Company__c = null;
   }
  }
}

//Trigger New & Old Company Updates (Owner, Name, Count Status etc)
if(updateCompanies.size()>0){
  Update updateCompanies.values();
}
}
logontokartiklogontokartik
I haven't looked at the complete code, but looking at the way you defined it has major flaws. Few things that need to be considered
  • You trigger code is recursive
  • You have defined, before inserts and trying to get Ids, which is not correct. (Ids wouldnt be available on before inserts)
Please check with your architects or any dev who has experience in building triggers,

Coming to your error. The Error is here
<pre>
/Set LC Name
     if(Ld.Company != oldLd.Company){
      ld.LC_Lead_Company__r.Name = Ld.Company;
      updateCompanies.put(ld.LC_Lead_Company__c, new LeadCompany__c(Id=ld.LC_Lead_Company__c));
     }
</pre>

Check to see if ld.LC_Lead_Company__c is null before you assign. or initialize the lc.ld.LC_Lead_Company__c. 

GlynAGlynA
Another suggestion - You should separate code that should run "before" from code that should run "after" into two triggers per object.  Put all the "before" code in the before trigger and all the "after" code in the after trigger.  (Better yet, create a class for each object and call the methods in the class from the triggers.)  To pick which code should run "before" and which should run "after", a good rule of thumb is this: If the code modifies fields on the object for which the trigger is firing, it should run "before" - this way you don't need to do DML on the records in the trigger.  If the code modifies objects other than the one for which the trigger is firing, it should run "after".  If you can help it, you should never do DML on the records that are in the trigger.  If you do, you have to deal with the possibility of the trigger running recursively.

Other things to keep in mind - "before insert" the records in the trigger will not have IDs.  So you can't create records that look up to the ones in the trigger.  On "delete", there is no trigger.new - use trigger.old instead.  "update" is the only event that has both trigger.new and trigger.old, and so it's the only time you can check for changed field values.  And finally, "after update" is the only event that can run recursively.

Let me know if you can use more help with this.  I'll check back periodically.

Glyn Anderson
Sr Developer | System Analyst | ClosedWon | closedwon.com
Certified Developer | Certified Advanced Administrator
Twitter: @GlynAtClosedWon