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
AmphitriteAmphitrite 

Apex class - DML Exception error

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger CaseUpdates caused an unexpected exception, contact your administrator: CaseUpdates: execution of BeforeUpdate caused by: System.ListException: DML statment found null SObject at position 0: Class.PropertyUpdatebyCode.PropertyUpdatebyCode: line 23, column 1". 

 

 

Getting this error anytime the for loop should be populating my properties array. 

 

 

Apex Class

 

public class PropertyUpdatebyCode{

      Public List<Case> lstNewCases = new List<Case>();
      Public List<Case> lstOldCases = new List<Case>();
    
        public void PropertyUpdatebyCode() {

 

        //variables
        Map<Id,Case>  mapVerifyOldCases=new Map<Id,Case>();
        List<Property_Account__c> properties = new list<Property_Account__c>();
        

 

        //populates map with old values for comparison
        For(Case CaseOld : lstOldCases){ mapVerifyOldCases.put(CaseOld.id,CaseOld);}
        

 

        //populates array for DML update expression
        For(Case CaseNew: lstNewCases){ 
            IF(CaseNew.Property__c!=Null && 

                CaseNew.XLS01__c==TRUE &&

                (CaseNew.IsClosed != mapVerifyOldCases.get(CaseNew.Id).IsClosed || 

                CaseNew.Property__c!= mapVerifyOldCases.get(Case New.Id).Property__c)){
                            
                properties.add(CaseNew.Property__r);
        
             }
        }     
        

        //DML updates if array isn't empty
        IF(properties.size()>0){
          
          update properties;
        
        }      
                        
                   
}        
}

 

 

Here is my trigger - which just populates the variable arrays for my apex class.

 

trigger CaseUpdates on Case (before insert,before update) 
{
         
           //instantiate class
           public PropertyUpdatebyCode  clsPropertyUpdatebyCode=new PropertyUpdatebyCode();

 

           //populate varibles
           clsPropertyUpdatebyCode.lstNewCases = Trigger.new;
           clsPropertyUpdatebyCode.lstOldCases = Trigger.old;

 

           //calls method
           clsPropertyUpdatebyCode.PropertyUpdatebyCode();
           
}

Best Answer chosen by Admin (Salesforce Developers) 
crop1645crop1645

Amphitrite:

 

You have a couple of issues here:

 

1. In your trigger, Trigger.old is not available during a before Insert; you'll need to do something like the below. In turn, you'll need to think through your logic to handle the insert use case 

 

 
trigger CaseUpdates on Case (before insert,before update) 
{
         
           //instantiate class
           public PropertyUpdatebyCode  clsPropertyUpdatebyCode=new PropertyUpdatebyCode();
 
           //populate varibles
           clsPropertyUpdatebyCode.lstNewCases = Trigger.new;
           clsPropertyUpdatebyCode.lstOldCases = Trigger.isUpdate ? Trigger.old : new List<Case>();
 
           //calls method
           clsPropertyUpdatebyCode.PropertyUpdatebyCode();
           
}

 2. It is not good practice to name your method within class PropertyUpdatebyCode the same as the class name as it runs the risk of confusion with the class's constructor.

 

3. It is hard to tell from your listing where line 23 is

 

4. It is also not best practice to do DML in before triggers; if the Case fails to insert/update (due to a validation rule or other trigger doing an add.error), then the DML on Property_Account__c will be rolled back.  You should convert your trigger to an after trigger (in which case Trigger.old will be available and the issue#1 goes away)

 

5. And the root of your error is that 'properties.add(CaseNew.Property__r);' won't work as coded because triggers do not bring into context values of related lists. Your after update/insert trigger will need to re-query the triggered Cases to fetch the related list property__r. Triggers only bring into context (that is, Trigger.new or Trigger.old) the Sobject itself, not related records, not lookup records. 

 

All Answers

crop1645crop1645

Amphitrite:

 

You have a couple of issues here:

 

1. In your trigger, Trigger.old is not available during a before Insert; you'll need to do something like the below. In turn, you'll need to think through your logic to handle the insert use case 

 

 
trigger CaseUpdates on Case (before insert,before update) 
{
         
           //instantiate class
           public PropertyUpdatebyCode  clsPropertyUpdatebyCode=new PropertyUpdatebyCode();
 
           //populate varibles
           clsPropertyUpdatebyCode.lstNewCases = Trigger.new;
           clsPropertyUpdatebyCode.lstOldCases = Trigger.isUpdate ? Trigger.old : new List<Case>();
 
           //calls method
           clsPropertyUpdatebyCode.PropertyUpdatebyCode();
           
}

 2. It is not good practice to name your method within class PropertyUpdatebyCode the same as the class name as it runs the risk of confusion with the class's constructor.

 

3. It is hard to tell from your listing where line 23 is

 

4. It is also not best practice to do DML in before triggers; if the Case fails to insert/update (due to a validation rule or other trigger doing an add.error), then the DML on Property_Account__c will be rolled back.  You should convert your trigger to an after trigger (in which case Trigger.old will be available and the issue#1 goes away)

 

5. And the root of your error is that 'properties.add(CaseNew.Property__r);' won't work as coded because triggers do not bring into context values of related lists. Your after update/insert trigger will need to re-query the triggered Cases to fetch the related list property__r. Triggers only bring into context (that is, Trigger.new or Trigger.old) the Sobject itself, not related records, not lookup records. 

 

This was selected as the best answer
k_bentsenk_bentsen

Because you named your method the same as your class, the system considers it a constructor method. When you instantiate your class in your trigger, your method is executing before you are able to populate the Case list values to it, at which point they are null and is why the error is being thrown. One way to fix the problem is include Case list parameters in your constructor method, and cut your trigger down to 1 line of code.

 

Class:

public class PropertyUpdatebyCode{

      Public List<Case> lstNewCases = new List<Case>();
      Public List<Case> lstOldCases = new List<Case>();
    
        public void PropertyUpdatebyCode(List<Case> passedNewCases, List<Case> passedOldCases) {

 

        //variables

        lstNewCases = passedNewCases;

        IstOldCases = passedOldCases;
        Map<Id,Case>  mapVerifyOldCases=new Map<Id,Case>();
        List<Property_Account__c> properties = new list<Property_Account__c>();
        

 

        //populates map with old values for comparison
        For(Case CaseOld : lstOldCases){ mapVerifyOldCases.put(CaseOld.id,CaseOld);}
        

 

        //populates array for DML update expression
        For(Case CaseNew: lstNewCases){ 
            IF(CaseNew.Property__c!=Null && 

                CaseNew.XLS01__c==TRUE &&

                (CaseNew.IsClosed != mapVerifyOldCases.get(CaseNew.Id).IsClosed || 

                CaseNew.Property__c!= mapVerifyOldCases.get(Case New.Id).Property__c)){
                            
                properties.add(CaseNew.Property__r);
        
             }
        }     
        

        //DML updates if array isn't empty
        IF(properties.size()>0){
          
          update properties;
        
        }      
                        
                   
}        
}

 

Trigger:

trigger CaseUpdates on Case (before insert,before update) 
{
   
           //instantiate class
           public PropertyUpdatebyCode  clsPropertyUpdatebyCode=new PropertyUpdatebyCode(Trigger.new, Trigger.old);

 

}

 

AmphitriteAmphitrite

Here is the fixed code - assigned the foriegn object id to a set variable and then queried for list before the dml update. Works as expected.

 

 

public class PropertyUpdate{

 

     Public List<Case> lstNewCases = new List<Case>();
     Public List<Case> lstOldCases = new List<Case>();

public void PropertyUpdatebyCode() {

    Map<Id,Case> mapVerifyOldCases=new Map<Id,Case>();
    Set<Id> propids = new Set<Id>();

    For(Case CaseOld : lstOldCases){ mapVerifyOldCases.put(CaseOld.id,CaseOld);}


   For(Case CaseNew: lstNewCases){
      IF(CaseNew.XLS01__c==TRUE &&
         (CaseNew.IsClosed != mapVerifyOldCases.get (CaseNew.Id).IsClosed ||
         CaseNew.Property__c!= mapVerifyOldCases.get(CaseNew.Id).Property__c)){

        propids.add(CaseNew.Property__c);

     }
   }

List<Property_Account__c> properties = [select id from property_account__c where id IN: propids];

IF(properties.size()>0){

 update properties;

}


}
}