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.
public class Pluck
{
public static Set<Id> ids(SObjectField field, List<SObject> record)
{
Set<Id> ids = new Set<Id>();
for (SObject record : records) ids.add((Id)record.get(field));
ids.remove(null);
return ids;
}
public static Set<String> strings(SObjectField field, List<SObject> records)
{
// etc.
}
}
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 parent Notes__c
values. We also tend to have a utility around for this functionality. You can support String
keys in addition to SObjectField
by using some sort of model class like FieldReference and method overloads.
public class GroupBy
{
public static Map<Id, List<SObject>> ids(SObjectField field, List<SObject> records)
{
Map<Id, List<SObject>> byId = new Map<Id, List<SObject>>();
for (SObject record : records)
{
Id key = (Id)record.get(field);
if (!byId.containsKey(key)) byId.put(key, new List<SObject>());
byId.get(key).add(note);
}
return byId;
}
}
Service Class
Class Declaration
You will need a service class for Notes
. I usually pluralize Services
in the class name, because the way I see it you will do many different things in most service classes you write.
public with sharing class NoteServices
{
// methods
}
Consolidating Note Bodies
You need to compress these Note
records into one String
. It is very important to use List<String>
because you will want to preserve order, and de-duplication is not particularly helpful (or likely to make an impact).
public static String consolidateBodies(List<Note> notes)
{
if (notes == null) return '';
List<String> bodies = new List<String>();
for (Note note : notes) bodies.add(note.Body);
return String.join(bodies, '\n');
}
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 this String
by the parent's Id
.
public static Map<Id, String> consolidateBodies(List<Note> notes)
{
final SObjectField PARENT = Note.ParentId
Map<Id, List<Note>> parentToNotes = GroupBy.ids(PARENT, [
SELECT Body FROM Note
WHERE ParentId IN :Pluck.ids(PARENT, notes);
ORDER BY Id DESC // if you want newest first
]);
Map<Id, String> bodies = new Map<Id, String>();
for (Id parentId : parentIds)
bodies.put(parentId, consolidateBodies(parentToNotes.get(parentId)));
return bodies;
}
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 you update
these records, make sure you handle DmlException
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.
public static List<SObject> syncParents(List<Note> notes)
{
Map<Id, String> bodies = consolidateBodies(notes);
List<SObject> parents = new List<SObject>();
for (Id parentId : parentIds)
{
SObject parent= parentId.getSObjectType().newSObject();
parent.put('Notes__c', bodies.get(parentId));
parent.Id = parentId;
parents.add(parent);
}
try { update parents; }
catch (DmlException dmx) { /*determine proper error handling*/ }
}
Best Answer
You could do this very easily with a Work flow rule.
Set up a Work Flow rule on the Account object.
Set the Evaluation Criteria to: created, and every time it’s edited In the Rule Criteria, set it to run if the formula evaluates to True
Set your formula to below
Then create a Workflow action of type, field update.
Set the the your Account note modified date field to
Save and activate the rule.
Now everytime an account is created this field is set to the current date, and if the account is edited and the Account Note field is edited, the field will be set to the current date.
Hope that helps.