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
Jack InsJack Ins 

Trigger after Update

Hi Everyone. 

I have a trigger on the Contract object that runs After Update.  My question is the trigger is only good for updating particular records but will fire after every record is updated.  To minimize the code that is running the first section of the code runs a set<String> to determine the Id's of the Contract records that will be effected.  After the Set is returned I have an if statement of:

 

if(!setC.isEmpty()) { do my stuff }

 

is this good practice so that the code section of "do my stuff" does not always run if the records being updated, based on the criteria of a "if" statement in my set<>, does not match?


Thanks :)

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

That is a typical design pattern, and it works quite well when you need to process records that meet a certain criteria. It is not the only way to do so, however. You can also follow this design pattern:

 

sobject[] updates = new sobject[0];
for(sobject trigger_record:trigger.new) {
  if(trigger_record.some_field != some_value) {
    continue;
  }
  updates.add(new sobject(parent_id=trigger_record.id, more_data=something_else));
}
update updates;

The only difference is that the method you proposes has to loop through all records, then loop through the matching records, while this design pattern skips that second loop while still only processing records that match your criteria. This is an inverted test example, where if the condition is met, the rest of the code is skipped for that record (the continue keyword immediately skips the current iteration and moves to the next). You could also just as easily do the following instead:

 

for(sobject trigger_record:trigger.new) {
  if(trigger_record.some_field == some_condition) {
    updates.add(new sobject(parent_id=trigger_record.id, more_data=something_else));
  }
}

The difference here is that the former method might be more readable if the contents of the if block is complex or longer. In the end, all three methods will perform approximately equally well.

 

In order to minimize the script statements used using your design pattern, though, you'll have to reference the record directly through the map. In my code examples, trigger_record is the current record; your code has to instead do one of the following:

 

for(id record_id:recordids) {
  sobject o = trigger.newmap.get(record_id); // uses an extra script statement per row
}

for(id record_id:recordids) {
  updates.add(new sobject(parent_id=record_id, other_data=trigger.newmap.get(record_id).some_value)); // slightly more difficult to read, especially if there are many values
}

// uses slightly more memory, but only two more script statements per batch
map<id,sobject> trigger_clone = trigger.newmap.clone();
trigger_clone.keyset().retainall(recordids);
for(sobject trigger_record:trigger_clone.values()) {
updates.add(...);
}

As I said, there are a number of equally valid ways to get the results you're looking for, and unless performance is really a major issue already, I'd just go with whatever you're most comfortable using instead of worrying about minor optimizations like this.

All Answers

sfdcfoxsfdcfox

That is a typical design pattern, and it works quite well when you need to process records that meet a certain criteria. It is not the only way to do so, however. You can also follow this design pattern:

 

sobject[] updates = new sobject[0];
for(sobject trigger_record:trigger.new) {
  if(trigger_record.some_field != some_value) {
    continue;
  }
  updates.add(new sobject(parent_id=trigger_record.id, more_data=something_else));
}
update updates;

The only difference is that the method you proposes has to loop through all records, then loop through the matching records, while this design pattern skips that second loop while still only processing records that match your criteria. This is an inverted test example, where if the condition is met, the rest of the code is skipped for that record (the continue keyword immediately skips the current iteration and moves to the next). You could also just as easily do the following instead:

 

for(sobject trigger_record:trigger.new) {
  if(trigger_record.some_field == some_condition) {
    updates.add(new sobject(parent_id=trigger_record.id, more_data=something_else));
  }
}

The difference here is that the former method might be more readable if the contents of the if block is complex or longer. In the end, all three methods will perform approximately equally well.

 

In order to minimize the script statements used using your design pattern, though, you'll have to reference the record directly through the map. In my code examples, trigger_record is the current record; your code has to instead do one of the following:

 

for(id record_id:recordids) {
  sobject o = trigger.newmap.get(record_id); // uses an extra script statement per row
}

for(id record_id:recordids) {
  updates.add(new sobject(parent_id=record_id, other_data=trigger.newmap.get(record_id).some_value)); // slightly more difficult to read, especially if there are many values
}

// uses slightly more memory, but only two more script statements per batch
map<id,sobject> trigger_clone = trigger.newmap.clone();
trigger_clone.keyset().retainall(recordids);
for(sobject trigger_record:trigger_clone.values()) {
updates.add(...);
}

As I said, there are a number of equally valid ways to get the results you're looking for, and unless performance is really a major issue already, I'd just go with whatever you're most comfortable using instead of worrying about minor optimizations like this.

This was selected as the best answer
Jack InsJack Ins
Excellent This is AWESOME. Thanks answers exactly what I needed to know.
Thanks You.
sfdcfoxsfdcfox

I also just realized you could do this:

 

sobject[] records_to_process = new sobject[0];
for(sobject trigger_record:trigger.new) {
  if(trigger_record.some_field == some_condition) {
    records_to_process.add(trigger_record);
  }
}
for(sobject process_record:records_to_process) {
  ...
}

Which avoids the need to keep the record ids, or use the trigger.newmap map, while still referencing just the records you'd like.

Jack InsJack Ins
Ask a pro and get a pro answer.... This is great I will def look into using this.
Thank you so much. :)