You need to sign in to do that
Don't have an account?
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();
}
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
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
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
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.
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);
}
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;
}
}
}