I want to convert my below trigger to use Dynamic Apex, so that I can avoid code repetition for other objects. This is what my trigger does :-
- I have a object called Incident__c and a custom field called Notes__c (Long Text Area).
- Whenever a Note get created(In the Incident__c object record), Notes__c field should be updated with Note body.
- When there are many Notes created, Notes__c field should append with all Note bodies.
- Also, when an existing 'Note' is edited, edited value should be updated in the Notes__c field.
- When a 'Note' is deleted, Notes__c field should also be updated according to deletion.
My trigger currently does this all. But I got another 4 objects I should support the same scenario. And all those objects have that 'Notes__c' field created. So I want to use Dynamic apex so there won't be repeated code, how to use Dynamic apex to get the APINames of objects I want and use SObject types ?
-----Helper class--------------
public with sharing class NoteTriggerHelper {
public static void insertNotesBodyToTextField(List<Note> notes){
Set<Id> incid = new Set<Id>();
for(Note n : notes){
incid.add(n.ParentId);
}
List<grc__Incident__c> incidents = [Select Id,Notes__c, (SELECT Id,Title, Body FROM Notes) from grc__Incident__c where Id IN :incid];
for(grc__Incident__c incident : incidents){
incident.Notes__c = getNotesString(incident.Notes);
}
update incidents;
}
private static String getNotesString(List<Note> notes){
String notesString = '';
for(Note nt : notes){
notesString = ' seperator ' + nt.Body + '\n' +notesString;
}
return notesString;
}
}
----------trigger----------------------
trigger NoteTrigger on Note (after insert, after update, after delete) {
if(Trigger.isAfter){
if(Trigger.isInsert){
NoteTriggerHelper.insertNotesBodyToTextField(Trigger.new);
}
if(Trigger.isUpdate){
NoteTriggerHelper.insertNotesBodyToTextField(Trigger.new);
}
if(Trigger.isDelete){
NoteTriggerHelper.insertNotesBodyToTextField(Trigger.old);
}
}
}
Best Answer
I agree with @crop1645 that DLRS is a good option here, but if you must roll your own it would look something like:
Utilities
Getting Parent Ids
I consider the following utility essential. It is easy to write, easy to test, and is so ubiquitous it will add a lot of syntactic sugar over time. It also means you don't have to cache these collections. We use sets to improve compatibility with queries.
Grouping
One of the first things you will need to do is be able to split the
Note
records from your trigger out by parent record so you can use them to generate specific parentNotes__c
values. We also tend to have a utility around for this functionality. You can supportString
keys in addition toSObjectField
by using some sort of model class like FieldReference and method overloads.Service Class
Class Declaration
You will need a service class for
Notes
. I usually pluralizeServices
in the class name, because the way I see it you will do many different things in most service classes you write.Consolidating Note Bodies
You need to compress these
Note
records into oneString
. It is very important to useList<String>
because you will want to preserve order, and de-duplication is not particularly helpful (or likely to make an impact).Getting Parent Notes
Once you know that you can get a
List<Note>
for a specific parent, you can pass in these grouped records to the above method to map thisString
by the parent'sId
.Using Note Bodies
You now have everything you need. Just putting it together, build up a list of parent records with the
Notes__c
field populated. When youupdate
these records, make sure you handleDmlException
specifically. Typically from a trigger I would simply map the errors back to the source record (in this case a child record). I have an example of how to do that in a different answer.