Recalcul des champs de formule Salesforce en Apex

Katie - Sep 10 '19 - - Dev Community

L’édition hiver ‘20 de Salesforce inclue une nouvelle classe Apex Formule – regardez ici un exemple de ses capacités.

James Hou a annoncé, dans l’excellent résumé de l’édition hiver ‘20 de Salesforce sur Reddit, traduit par Windyo :

Recalcul des formules en Apex : c’est ENORME.

Cette release permet de calculer les formules, en batch, sans opération DML.

De fait, ça permet donc de laisser les champs formules gérer les calculs un peu complexes, et d’en utiliser les résultats en Apex sans sauvegarder.

Et c’est vrai !

Voyons un petit exemple :

@isTest
public class UnTest {
    static testMethod void executerTest() {
        ObjetParent __c parent = new ObjetParent__ c(
            Name = 'Un parent',
            Code__c = 'ABAB'
        );
        INSERT parent;
        ObjetEnfant __c enfant = new ObjetEnfant__ c(
            Name = 'Un enfant',
            Code__c = 'XYXY',
            Parent__c = parent.Id
        );
        System.assertEquals(NULL, enfant.Formule_Code_Concatene__c);
        Test.startTest();
        Formula.recalculateFormulas(new List<ObjetEnfant__c>{enfant});
        Test.stopTest();
        System.assertEquals('ABAB|XYXY', enfant.Formule_Code_Concatene__c);
    }
}

Notez que l’objet dit «enfant» n’existe pas dans la base de données.

Je ne l’ai pas encore enregistré avec une commande INSERT.

Et quand même, après la commande Formula.recalculateFormulas(), le valeur de son champ Formule_Code_Concatene__c est ABAB|XYXY.

Notez: Dans ce cas, la formule est:

Parent__r.Code__c & "|" & Code__c


Erreur connu

Si vous essayez dans un contexte de déclencheur BEFORE, vous verrez peut-être une erreur System.DmlException qui annonce UNKNOWN_EXCEPTION et Cannot set the value of a calculated field.

Jusqu'ici, il me paraî qu'il faut éviter d'exécuter Formula.recalculateFormulas() avec les objets SObject que vous désirez mettre à jour.

S'il faut lire les contenus du champ de formule Contact.Formule_1__c pour décider s'il faut mettre à jour le champs Contact.Champs_Personnalise__c, faîtes ainsi :

private void xyzzy(List<Contact> contacts) {
    Map<Contact, Contact> contactsEtLeursCopies = new Map<Contact, Contact>();
    for ( Contact c : contacts ) { contactsEtLeursCopies.put(c, c.clone()); }
    Formula.recalculateFormulas(contactsEtLeursCopies.values());
    for ( Contact c : contacts ) {
        Contact cCopie = contactsEtLeursCopies.get(c);
        if ( cCopie.Formule_1__c == 'Bonjour' ) {
            c.Champs_Personnalise__c = 'le monde';
        }
    }
}

Je ne sais pas lequel est plus performant : une petite requête SOQL ou cet approche-ci de faire des copies des SObject. Qu'en pensez-vous ?

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .