1

I have created an object with multiple formula fields. Some formula fields are simple and some are complex.

I want to get calculated values of few formula fields.

To get the value of a formula field, I used Formula.recalculateFormulas(List<SObject> obj) which returns a sobject with all formula fields calculated values. It works fine for simple formula fields but fails sometime giving an UnexpectedException.

So, I do not want to get calculated values of all formula fields.

Is it possible to get calculated value of only one or two formula fields only ?

1 Answer 1

2

At time of writing, it's pretty much an all-or-nothing affair.

  • Formula.recalculateFormulas() re-calculates all formulas
  • Sobject's recalculateFormulas() method also recalculates all formulas, except for cross-object formulas, but each use counts towards one additional SOQL query and it only operates on a single record

In this situation, you (most likely) can't avoid using a query (unless you can provide the data required to calculate all of your formulas). In fact, if you want to only get updated values for some of your formulas, re-querying your target records is likely the easiest/most efficient way to do it (though if you want updated formula values, you'll have to perform a DML insert/update/upsert as appropriate first).

+edit:

I had an idea where Formula.recalculateFormulas() may be able to do its work if you provided the parent object inside of the records that you wanted to recalculate formulas for.

Spoiler: It doesn't work like in the way I would expect...

unless you happen to have a valid object Id in your org for the related object

i.e.

// Provided that you have a formula on Opportunity that references the Amount field
//   and some cross-object formulas that reference account data...
// I had a feeling this might work (but it doesn't, it generates some internal
//   error code)
Account myDummyAccount = new Account(
    Id = '001000000000001',
    ParentId = '001000000000002',
    Name = 'DummyAcct'
);

Opportunity opp = new Opportunity(
    // This is not a typo, you can set the nested SObject of a related field
    //   like this without issue (most of the time)
    Account = myDummyAccount
    Amount = 10
);

List<FormulaRecalcResult> results = Formula.recalculateFormulas(new List<Opportunity>{opp});

However, it can still consume a query and generates a FormulaRecalcFieldError (or multiple errors, if you have multiple formulas referencing the same object).

This important information I took from playing around with this is as follows:

  • Even though it generates some errors, you are still able to re-calculate and use formula fields that are entirely on-object (as opposed to cross-object, e.g. Account.Name in a formula field on Opportunity)
  • If you don't have (or try to assign) a record Id to an in-memory object instance, Formula.recalculateFormulas() does not consume a query
  • If you have a valid Id in your org for the target related object, you can use that (i.e. if 001000000000001 is a valid Account Id, you could specify that in the AccountId field on an Opportunity). You won't encounter errors, you won't use a query, and you'll get the correct values from your related object

Final example code:

Account someAcc = new Account(
    Id = '0013m000028yeyK', // had to get this from a query, but it doesn't need
                            //   to be a query in this transaction
    ParentId = '001000000000002AAA',
    Name = 'testAcct'
);

Opportunity opp2 = new Opportunity(
    //Id = '006000000000001', // If you include an Id (or the record has an Id
                              //   from a DML insert), then recalculating formulas
                              //   will consume a query.
                              // Otherwise, (as in this case) no query is consumed
    //Account = someAcc,
    AccountId = someAcc.Id, // You'd need to set the relationship field, not the 
                            //   embedded object
    Amount = 100
);

List<FormulaRecalcResult> results = Formula.recalculateFormulas(new List<Opportunity>{opp2});
system.debug(opp2.Justa_Value__c); // On-object formula, pulls Opp.Amount
system.debug(opp2.Account_Name__c); // Cross-object formula, pulls account name
                                    //   from related account

// You won't see any errors here, provided you used a valid id
for(FormulaRecalcResult res :results){
    system.debug(res);
}
1
  • The kicker for my edit is that you'll still probably need to query for a related record Id (unless you're storing records that are already inserted by the time you'd need to use this). Unless you're really pressed for queries, using a query to get updated formula results is likely the simplest, easiest, and most reliable way to do this.
    – Derek F
    Sep 19, 2020 at 17:59

You must log in to answer this question.

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