I have a trigger that copies values from child records to a field on the parent record. The trigger runs on insert, update and delete. The problem is occurring when I try and delete the last child record, the value in the parent field does not get cleared. If there are no child records, then the field on the parent should be null, but the last value remains. The delete does work if there are multiple child records and I delete one of the records, that value is removed from the parent field. The problem is occurring only when the last child record is deleted and the value is not cleared on the parent field.

Here is my code:

global class BrandCopyToAccount implements ITriggers.HandlerInterface {

List<Brand__c> newCollection = trigger.new;
Map<Id, Brand__c> oldCollection = (Map<Id, Brand__c>)trigger.oldMap;
Boolean isInsert = trigger.isInsert;
Boolean isUpdate = trigger.isUpdate;
Boolean isDelete = trigger.isDelete;

global void handle() {

private Set<Id> getAccountIds() {
    Set<Id> accountIds = new Set<Id>();
    if(isInsert || isUpdate) {
        for(Brand__c b : newCollection) {
            if(isInsert || b.Brand__c != oldCollection.get(b.Id).Brand__c) accountIds.add(b.Account__c);
    if(isDelete) {
        for(Brand__c b : oldCollection.values()) {
    return accountIds;

private void copyBrandsToAccount(Set<Id> accountIds) {
    String brand = '';
    Map<Id, Account> accountsToUpdate = new Map<Id, Account>();
    if(!accountIds.isEmpty()) {
        Map<Id, Account> mapAccounts = new Map<Id, Account>([select Id, Brands__c from Account where id in: accountIds]);
        for(Brand__c b : [select Brand__c, Account__c from Brand__c where Account__c in: accountIds]) {
            if(!mapAccounts.isEmpty() && mapAccounts.size() > 0) {
                if(mapAccounts.containsKey(b.Account__c)) {
                    Account a = mapAccounts.get(b.Account__c);
                    if(brand.indexOf(b.Brand__c) == -1) {
                        brand += b.Brand__c + ';';
                        a.Brands__c = brand.substring(0,brand.length()-1);
                        accountsToUpdate.put(a.Id, a);
        if(!accountsToUpdate.isEmpty() && accountsToUpdate.size() > 0) {
            update accountsToUpdate.values();

You are only updating the Account if there is a Brand__c record in the database when you query. In the case where a Brand__c record is the last one on an Account and it's deleted, there will be no Brand__c that is returned to your query in the for loop, and therefore, you will never update the Brands__c field again until there is a Brand__c record for that Account again.

To fix this, you will need to make sure you update all affected Accounts, even if there are no Brand__c records for them. For example, you could use the Brand__c query as a subquery to an Account query, and loop over the Accounts instead of Brands. Build your concatenated String field on Account fresh every time, and you don't have to worry about modifying the existing field when a Brand is added or deleted.

This loop should basically replace the for loop and query that you have in place:

for(Account a : [
    select Id, Brands__c,
    (select Brand__c from Brands__r)
    from Account
    where Id in :accountIds])
    a.Brands__c = '';
    for (Brand__c brand : a.Brands__r)
        a.Brands__c += brand.Brand__c + ';';
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.