Recalculating Salesforce Formula Fields in Apex
Tags: salesforce, database, news
Published: 2019-09-10 18:18:35

---
title: Recalculating Salesforce Formula Fields in Apex
description: Winter 20 release
published: true
tags: salesforce,database,news
canonical_url: https://katiekodes.com/recalculate-formulas-salesforce-apex/
---

Salesforce Winter ‘20 has a new `Formula` class in Apex – check out what it can do.

[James Hou](https://github.com/tsalb) pointed out, quoted in [Windyo](https://github.com/Windyo)’s [excellent abridged Winter ‘20 release notes on Reddit](https://old.reddit.com/r/salesforce/comments/d1qc3r/winter_20_release_notes_abridged_edition/) :

> [Formulas recalculation in APEX](http://releasenotes.docs.salesforce.com/en-us/winter20/release-notes/rn_apex_new_classes_methods.htm#rn_apex_new_classes_methods_new_classes): That is HUGE.
> 
> You can calculate formulas without a DML, in batch.
> 
> Let that sink in…. you can basically have formulas lift heavy calculations and do it in an Apex class _ **without saving** _.

And it’s true!

Here’s an example in the form of a unit test:

```java
@isTest
public class ATest {
	static testMethod void runTest() {
		ParentObject __c parent = new ParentObject__ c(
			Name = 'Parent',
			Code__c = 'ABAB'
		);
		INSERT parent;
		ChildObject __c child = new ChildObject__ c(
			Name = 'Child',
			Code__c = 'XYXY',
			Parent__c = parent.Id
		);
		System.assertEquals(NULL, child.Concatenated_Formula_Field__c);
		Test.startTest();
		Formula.recalculateFormulas(new List<ChildObject__c>{child});
		Test.stopTest();
		System.assertEquals('ABAB|XYXY', child.Concatenated_Formula_Field__c);
	}
}
```

Note that the object named `child` _**does not exist**_ yet in the database – it’s an in-memory `SObject` only.

I have _not_ yet saved it to the database with an `INSERT` command.

And yet, after running `Formula.recalculateFormulas()`, the value of the field `Concatenated_Formula_Field__c` is `ABAB|XYXY`.

_Note: In this case, the formula itself is:_

```
Parent__r.Code__c & "|" & Code__c
```

---

## Error Message Workaround

FYI, if you try to use `Formula.recalculateFormulas()` in a `BEFORE`-context trigger to ensure that you condition logic upon the values of formula fields, you might get a `System.DmlException` that says, `UNKNOWN_EXCEPTION` and `Cannot set the value of a calculated field`.

So far, the workaround I've come up with is to avoid actually running `Formula.recalculateFormulas()` against the `SObject` whose field values you actually intend to set with the trigger code.

If you need to read `Contact.Formula_1__c` so as to decide what to put into `Contact.Custom_Text_Field__c`, do the following:

```java
private void setCustomField(List<Contact> contacts) {
	Map<Contact, Contact> contactsAndTheirClones = new Map<Contact, Contact>();
	for ( Contact c : contacts ) { contactsAndTheirClones.put(c, c.clone()); }
	Formula.recalculateFormulas(contactsAndTheirClones.values());
	for ( Contact c : contacts ) {
		Contact cClone = contactsAndTheirClones.get(c);
		if ( cClone.Formula_1__c == 'Hello' ) {
			c.Custom_Text_Field__c = 'World';
		}
	}
}
```

Got a better idea?  Have thoughts on whether this is better or worse than a small SOQL query in a before-trigger?  Please comment; I'd love to hear it!

---

## Further Reading:

* [Recalculate formulas on the fly with the new Formula class – Salesforce Winter ’20](http://thecodery.io/recalculate-formulas-on-the-fly-with-the-new-formula-class-salesforce-winter-20/) by Sebastián Kessel, who dives deeper into code examples