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 ?

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);
}
| improve this answer | |
  • 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 at 17:59

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.