I am new to apex. I need to write a trigger on the Account object.

Whenever account is added or updated, I will check if the Description field is not empty or was changed. The account description field will contain the child account names. ```

  • 2
    Google for how to use maps to avoid a query inside a loop. But using the default parent reference on Account or adding your own lookup would make for a more robust and scalable system than the comma separated list of names.
    – Keith C
    Nov 7, 2021 at 14:14

1 Answer 1


You need to use the Aggregate-Query-Update Pattern. That is, you need to first get all the child names you're interested in finding, grabbing those children, then performing any updates you need (in this, case, creating child accounts). That would approximately look like:

trigger OnAccountChangeTrigger on Account(after insert,after update) {
    Map<Id, Set<String>> oldChildNamesByParentId = new Map<Id, Set<String>>();
    Map<Id, Set<String>> newChildNamesByParentId = new Map<Id, Set<String>>();
    Map<String, Account> postChildAccountsByName = new Map<String, Account>();
    Map<String, Account> preChildAccountsByName = new Map<String, Account>();
    Set<String> allChildNames = new Set<String>();
    Account[] childAccountsToUpsert = new Account[0];

    // Helper method //
    void populateChildDataMaps(Account[] records, Map<Id, Set<String>> childNamesByParentId, Set<String> allChildNames) {
        for(Account record: records) {
            Set<String> childNames = new Set<String>();
            if(record.Description != null) {
            childNamesByParentId.put(record.Id, childNames);

    // Aggregate //
    populateChildDataMaps(Trigger.new, newChildNamesByParentId, allChildNames);
    if(Trigger.isUpdate) {
        populateChildDataMaps(Trigger.old, oldChildNamesByParentId, allChildNames);
    for(String childName: allChildNames) {
        preChildAccountsByName.put(childName, new Account(Name=childName, ParentId=null));
        postChildAccountsByName.put(childName, new Account(Name=childName, ParentId=null));

    // Query //
    for(Account record: [SELECT Name, ParentId FROM Account WHERE Name = :allChildNames]) {
        preChildAccountsByName.put(record.Name, record.clone(true, false, false));
        postChildAccountsByName.put(record.Name, record.clone(true, false, false));
    // Update //
    if(Trigger.isUpdate) {
        for(Account record: Trigger.old) {
            for(String oldChildName: oldChildNamesByParentId.get(record.Id)) {
                postChildAccountsByName.get(oldChildName).ParentId = null;
    for(Account record: Trigger.new) {
        for(String newChildName: newChildNamesByParentId.get(record.Id)) {
            postChildAccountsByName.get(newChildName).ParentId = record.Id;
    // Only perform DML on records that were modified
    for(String childName: postChildAccountsByName.keySet()) {
        if(preChildAccountsByName.get(childName) != postChildAccountsByName.get(childName)) {
    Database.upsert(childAccountsToUpsert, Account.Id);

Some additional optimization should be possible from here, but this is the basic design of what you're looking for.

  • any particular reason why did you use record.clone(true, false, false) before adding it to the map? Nov 8, 2021 at 1:56
  • 2
    @NagendraSingh Because we're storing objects in those maps, they need to be distinct objects in memory, or an update to one map's accounts would update both, and we wouldn't see any changes correctly. I clone twice just to make sure I have the same fields populated in each copy.
    – sfdcfox
    Nov 8, 2021 at 2:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .