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. ```
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. ```
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) {
childNames.addAll(record.Description.split(','))
}
childNamesByParentId.put(record.Id, childNames);
allChildNames.addAll(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)) {
childAccountsToUpsert.add(postChildAccountsByName.get(childName));
}
}
childAccountsToUpsert.sort();
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.
record.clone(true, false, false)
before adding it to the map?
Commented
Nov 8, 2021 at 1:56