+ Start a Discussion
SeanCenoSeanCeno 

Sum Multiple String Values to SObjectField

In an attempt to clean up my org and remove some fields, I'm trying to modify code that grabs Trade totals from one specific Fund Number and applies to them to the corresponding fields, and instead combine Fund Numbers and sums them to one field. Here is my example with code snippets:
public static final Set<String> FUND_NUMBERS = new Set<String> {
        '3915',
        '3917',
    };

    // All amounts/shares
    public static final Map<String, SObjectField[]> FIELDMAP_TOTAL = new Map<String, SObjectField[]>  {
        '3915' => new SobjectField[] { Account.Total_NS_Income_II_Sales__c , Account.Total_NS_Income_II_Shares__c },
'3917' => new SobjectField[] { Account.Total_NS_Income_II_T_Share_Sales__c, Account.Total_NS_Income_II_T_Shares__c },
    };
        // Fetch all the trades for these accounts
        Trades__c[] tradesList = [
            SELECT Name
                 , Dollar_Amount_of_the_transaction__c
                 , Fund_Number__c
                 , Number_of_Shares_of_the_transaction__c
                 , Resolved_Firm_Trading_ID__c
                 , Trade_Date__c
              FROM Trades__c
             WHERE Resolved_Firm_Trading_ID__c IN :accountIds
               AND Resolved_Firm_Trading_ID__c <> NULL
               AND Fund_Number__c IN :FUND_NUMBERS
               AND Trade_Date__c != NULL
               AND Dollar_Amount_of_the_transaction__c >= 0
               AND Number_of_Shares_of_the_transaction__c >= 0
        ];

            Decimal amount = trade.Dollar_Amount_of_The_Transaction__c;
            Decimal shares = trade.Number_of_Shares_of_the_transaction__c;
            String fn = trade.Fund_Number__c;
            SobjectField f0, f1;

            // Always apply to totals
            if (true) {
                f0 = FIELDMAP_TOTAL.get(fn)[0];
                f1 = FIELDMAP_TOTAL.get(fn)[1];

                account.put(f0, (Decimal) account.get(f0) + amount);
                account.put(f1, (Decimal) account.get(f1) + shares);
            }
        }

        // Done, try to update
        update accountMap.values();
    }
Now if I want to combine Fund Numbers 3915 & 3917 to be summed into the same fields, like so:
'3915' + '3917' => new SobjectField[] { Account.Test_Total_Sales__c, Account.Test_Total_Shares__c}
I get thrown an "Attempt to de-reference a null object" error on line 36 (in first snippet), the f1 = FIELDMAP_TOTAL.get(fn)[1];.

What is the proper way to structure this map to combine Fund Numbers?
pigginsbpigginsb
It might be helpful to see more of your code. Are you saying that the f0=FIELDMAP_TOTAL.get(fn)[0] line does not throw a null pointer, but that the f1 assignment does? That would only happen if the fn key had only one element in the resultant array. I don't expect that you'd have an array with a single value if you are clearly adding two when the map is instantiated.

It seems more likely that lines 38 or 39 would throw a null pointer if the amount or shares values from the trade record were null, since you cannot use a null value in a calculation. You would need to include some logic to assign zero if the values taken from trade are null. Even if the null pointer is from the f1 assignment line, it would be good precaution to ensure that you are working with non-null values in your calculations.

 
SeanCenoSeanCeno
Thanks for the reply.

Actually both 38 and 39 throw null pointer exceptions if I comment one out. And I do have some logic that assigns zero to the values if there are no trades to calculate:
 
public static final Set<SObjectField> FIELD_ZERO_SET = new Set<SObjectField> {
        Account.Total_NS_Income_II_Sales__c,
        Account.Total_NS_Income_II_Shares__c,
        Account.Total_NS_Income_II_T_Share_Sales__c,
        Account.Total_NS_Income_II_T_Shares__c,

    public static void execute (Set<Id> accountIds, List<Account> accountsList) {
        new Account_RollupTrades().execute(accountIds);
    }

    public void execute (Set<Id> accountIds) {
        // List of accounts to eventually be updated
        Map<Id, Account> accountMap = new Map<Id, Account>();

        // Build the list
        for(Id accountId : accountIds) {
            Account account = new Account(Id = accountId);

            // Zero out fields
            for(SObjectField sobjectField : FIELD_ZERO_SET) {
                account.put(sobjectField, 0);
            }

            // Done init
            accountMap.put(accountId, account);
        }

About the fn key, are you saying that I need to add as many keys as there are fund numbers being added together? Something like:
f0 = FIELDMAP_TOTAL.get(fn + f2 + ....fx)[0];
f1 = FIELDMAP_TOTAL.get(fn + f2 + ....fx)[1];
pigginsbpigginsb
When using a map, a null value will be returned if you attempt to use a key that does not exist. So you should not expect to get a useful value from a map, unless it contains the key you are hoping to use.
SeanCenoSeanCeno
Thanks, bjpiggins. I believe the solution to my problem would be in rewriting the following map:
public static final Map<String, SObjectField[]> FIELDMAP_CY = new Map<String, SObjectField[]>  {
        '3915' => new SobjectField[] { Account.YTD_NS_Income_II_Sales__c },
        '3917' => new SobjectField[] { Account.YTD_NS_Income_II_T_Share_Sales__c },

To something like:
public static final Map<SObjectField[], List<string>> FIELDMAP_CY = new Map<SObjectField[], List<String>>();
    List<String> IncomeII = new List<String>{'3912','3915'};
    FIELDMAP_CY.put(Account.YTD_NS_Income_II_Sales__c,IncomeII);

So that I am able to take the values from both '3912' and '3915' and sum them into one field.