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
MBrady325MBrady325 

Updating one object when a custom object is created

I use a custom object called vftimer to log hours, and it is part of a managed object, so I'm unable to make it part of a master-child relationship and use roll-up summaries.  When a vftimer object (Timed Item) is created with an amount of time in the Time field, it is associated with a case, and there is a custom field on the case for Total Hours Logged.  I want the Total Hours Logged field to be updated by adding the amount of the Time in the Timed Item object to the total.  Here's what I think I need to do:

 

trigger add_time_to_total on vftimer__TimedItem__c (after insert) { 

for (vftimer__TimedItem__c t : trigger.new){

ID case_ID = t.vftimer__Case__c;

case timer_case = [select id,Total_Hours_Logged__c from case where id = :case_ID limit 1];

timer_case.Total_Hours_Logged__c += t.vftimer__Time__c;

upsert timer_case;

}

}

 

When I try to create a new Timed Item, I get this error:

 

Apex trigger add_time_to_total caused an unexpected exception, contact your administrator: add_time_to_total: execution of AfterInsert caused by: System.QueryException: List has no rows for assignment to SObject: Trigger.add_time_to_total: line 4, column 19

 

I'm obviously doing something wrong here; is the SOQL query incorrect?  Is there a better way to look up the case that is associated with the Timed Item and update it?

Best Answer chosen by Admin (Salesforce Developers) 
aalbertaalbert

There are two issues I see with this code. For starters, you have a SOQL query inside a for loop so you run the risk of hitting a governor exception if this trigger executes against more than 20 records. Below is a refactored trigger you can try. I haven't compiled this so there could be some typos/errors, but it shows you the way to handle bulk records by querying all records in a single query, then iterating across the result set after.

 

 

trigger add_time_to_total on vftimer__TimedItem__c (after insert) { 
Set<ID> caseIds = new Set<ID>{};
Map<String,vftimer__TimedItem__c> timers = new Map<String, vftimer__TimedItem__c>{};

for (vftimer__TimedItem__c t : trigger.new){
    if(t.vftimer__Case__c != null){
    caseIds.add(t.vftimer__Case__c);
    timers.put(t.vftimer__Case__c,t);
}
}	
if(casesIds!=null && casesIds.size()>0){
List<Case> casesToUpdate =  [select id,Total_Hours_Logged__c from Case where ID in :caseIds];
for (Case c: casesToUpdate){
		if(timers.get(c.Id)!=null){
			c.Total_Hours_Logged__c += timers.get(c.id).vftimer__Time__c;
		}
update casesToUpdate;
} //end for loop
} //end if statement
}

 

 

All Answers

bob_buzzardbob_buzzard

In this line:

 

 

case timer_case = [select id,Total_Hours_Logged__c from case where id = :case_ID limit 1];

 

 

There is an assumption that there will always be a case returned, which doesn't appear to be the situation.

 

Change this to something like:

 

 

List<Case> timer_cases = [select id,Total_Hours_Logged__c from case where id = :case_ID limit 1];
if (!timer_cases.isEmpty())
{
   Case timer_case=timer_cases[0];

   // the rest of your code goes here
}

 

and this will protect you when there are no matches

 

 

aalbertaalbert

There are two issues I see with this code. For starters, you have a SOQL query inside a for loop so you run the risk of hitting a governor exception if this trigger executes against more than 20 records. Below is a refactored trigger you can try. I haven't compiled this so there could be some typos/errors, but it shows you the way to handle bulk records by querying all records in a single query, then iterating across the result set after.

 

 

trigger add_time_to_total on vftimer__TimedItem__c (after insert) { 
Set<ID> caseIds = new Set<ID>{};
Map<String,vftimer__TimedItem__c> timers = new Map<String, vftimer__TimedItem__c>{};

for (vftimer__TimedItem__c t : trigger.new){
    if(t.vftimer__Case__c != null){
    caseIds.add(t.vftimer__Case__c);
    timers.put(t.vftimer__Case__c,t);
}
}	
if(casesIds!=null && casesIds.size()>0){
List<Case> casesToUpdate =  [select id,Total_Hours_Logged__c from Case where ID in :caseIds];
for (Case c: casesToUpdate){
		if(timers.get(c.Id)!=null){
			c.Total_Hours_Logged__c += timers.get(c.id).vftimer__Time__c;
		}
update casesToUpdate;
} //end for loop
} //end if statement
}

 

 

This was selected as the best answer
MBrady325MBrady325

Thanks, that seems to work!  Now I just need to figure out how to deploy it...