-1

I tried separating the trigger and class, but now I am unable to populate the account field, ProductsOwned__C with the set of string elements, mapTemp. I am looking to make edits on the asset(s), take the asset's productfamily__c value and add those values to the accounts ProductsOwned__c field. Any suggestions? Thank you.

Updated Class

public class AccountActiveProducts {

    public static void updateAccounts(List<Asset> assetLists){
        Map<Id, Account> mapAccount = new Map<Id, Account>();
        Map<Id, String> mapTemp = new  Map<Id, String>();
        Set<String> assetCollection = new Set<String>();
        List<Id> ParentIds = new List<Id>();

        if(Trigger.isInsert || Trigger.isUpdate){ 
        for(Asset asset: assetLists){

            if(asset.Status!= null ||asset.Status !='Retired' || asset.Status!= 'Obsolete' && asset.AccountId != null )

            ParentIds.add(asset.AccountId);
            assetCollection.add(asset.ProductFamily__c);  
            mapTemp.put(asset.Id, asset.ProductFamily__c);
        }
{

        mapAccount = new Map<Id, Account>([Select Id, ProductsOwned__c, (Select Id, ProductFamily__c from Assets Where Id In: parentIds) From Account]);

        for(Asset asst: assetLists){
            Account a = mapAccount.get(asst.AccountId);
            assetCollection.add(asst.ProductFamily__c);
            a.ProductsOwned__c =+ asst.ProductFamily__c;
            }

        String temp = '' + assetCollection;

        for(Account accta: [Select Id, ProductsOwned__c from Account Where Id In: parentIds]){
            accta.ProductsOwned__c = temp;
            mapAccount.put(accta.Id, accta);
        }
    }
        try{  
        if(mapAccount.size() > 0){
            update mapAccount.values();
        } 
        }
            catch(Exception e){
                System.debug('The follow exception has occured: ' + e.getMessage());
            }
        }
        }

}

Updated Trigger

trigger AssetPrimaryTrigger on Asset (before insert, before update, after insert, after update, before delete, after delete) { if(Trigger.isBefore){ if(Trigger.isInsert){
} if(Trigger.isUpdate){ } if(Trigger.isDelete){ }

}

if(Trigger.isAfter){ if(Trigger.isInsert){ AccountActiveProducts.updateAccounts(trigger.new); } if(Trigger.isUpdate){ } if(Trigger.isDelete){ }

}    

}

Original Trigger

I am attempting to link a set to a string field (String por =+ '' + assetCollection). However when I do a mass update on the assets, the account field is only grabbing one of the asset updates. Is there a way to set the set in the mapTemp field and assign that to a string field? From there I would like to take the account ProductsOwned__c field and assign it to the new string field. Thank you.

trigger Asset5 on Asset (after insert, after update) {
    if(Trigger.isAfter){
    if(Trigger.isUpdate){
        try{
            for(Asset a:trigger.old){
             String s = a.ProductFamily__c;
             Account account = [Select Id, ProductsOwned__c from Account Where Id =: a.AccountId];
             List<Asset> listAsset = [Select Id, ProductFamily__c, Status from Asset where (AccountId =:account.Id) AND (Status != 'Retired' OR Status != 'Obsolete') ];
             Map<Id, Set<String>> mapTemp = new Map<Id, Set<String>>();
                 for(Asset asset: listAsset){
                    Set<String> assetCollection = new Set<String>();
                    assetCollection.add(asset.ProductFamily__c);
                    mapTemp.put(asset.Id, assetCollection);
                    System.debug('---------------------' + mapTemp);
                    String por =+ '' +assetCollection;
                    account.ProductsOwned__c = por;
                }

                update account;
            }
        }
        catch(Exception e){
            System.debug(e);
        }
     }
   }
}
  • I'm not sure I understand your question. What I would say, however, that doing the non-bulkified query for Account in a for loop across the trigger's assets is going to break this trigger as soon as 99 assets or more are being handled by the trigger. This is against best practice and you need to move this query outside the for loop, using a bulkified query against collected account IDs. – Phil W Apr 15 at 20:03
  • 1
    This question appears to be very similar to the one you asked almost a week ago. The suggestion at that time was to use DLRS instead of trying to roll your own. Is there a reason why you don't want to use the DLRS tool? – Derek F Apr 15 at 20:11
  • Hi @DerekF I did use the DLRS tool and it seemed to work, however the business has asked that we keep all of the logic within code. – AL 600 Apr 15 at 21:03
2

Your trigger logic is incorrect in such a way that you only ever consider one record at a time - that is, you don't actually accumulate values across loop iterations.

             for(Asset asset: listAsset){

Here, you initialize a new assetCollection variable for each Asset - not for each Account. That's because it's inside the inner for loop.

                Set<String> assetCollection = new Set<String>();
                assetCollection.add(asset.ProductFamily__c);
                mapTemp.put(asset.Id, assetCollection);
                System.debug('---------------------' + mapTemp);
                String por =+ '' +assetCollection;
                account.ProductsOwned__c = por;

Then, here, you assign the Account field to equal the string representation of the Set, within the loop over its Assets. As a result, each Account will only get a single value - the ProductFamily__c of whichever Asset your code happens to touch last.

Fixing This Code

Your code is short on a number of best practices. I will note a few here that I would recommend you investigate and apply.

  1. Trigger handler pattern. Your business logic should be factored into a separate class.
  2. No empty exception handlers! Never swallow an exception with a debug statement; that makes debugging really hard and risks losing data integrity in your system.
  3. Bulkification. You need to be querying outside your loops and processing collections of records. See the Bulk Apex Triggers unit on Trailhead for more.

The third is the one that will most likely bite you first (watch what happens when you process a lot of records - you'll start getting SOQL and DML limit exceptions).

Better Approach

Just use Declarative Lookup Rollup Summaries to roll up ProductFamily__c from Asset to Account in Concatenate Distinct mode. Then you don't have to write a line of code, and to be honest you have a lot more work to do to make this resilient across all use cases.

  • Thank you for the suggestions. I will modify the code based on them. – AL 600 Apr 15 at 21:19

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.