Problème de cache sur les expressions calculées

Bonjour,

J’ai besoin d’aide sur un champ calculé qui semble garder le row_id de la première instance d’objet consultée.
C’est à dire que j’affiche le formulaire de mon objet de row_id 40, je reviens sur la liste, j’affiche le formulaire de l’objet 38, mais obj.getrowid() continue de me renvoyer 40.

Voici mon expression calculée

(function(){  
    var res = 0;  
    var personal = 0;

    console.log(obj);

    if (!obj.isNew()) {  
        var flowId=obj.getRowId();  
        
        if (flowId != "")
        {
	        var sql="select count(rci_data.row_id) from rci_data inner join rci_flo_dat on rci_fludata_data_id = rci_data.row_id where rci_dat_personal= '1' and rci_flodat_flo_id = '" + flowId + "'";
	        personal=grant.simpleQueryAsLong(sql);  
        }
    }  
    return personal != 0;  
})()

/health

Version=4.0.P25
BuiltOn=2020-11-04 00:18 (revision 99559caac5ed624fa5cd04a2ae438cbb833d6478)

Je ne comprends pas d’où vient l’erreur, avec vous des pistes ?

Merci !

On va vérifier mais ce problème ne me dit rien. avez vous un hook getTargetObject sur cet objet ?

Sinon un champ calculé qui fait du SQL à chaque lecture n’est pas optimum (surtout en liste), et a plus intérêt à être calculé une seule fois à chaque preSave et être persistant/non modifiable.

Non pas de getTargetObject. J’ai regardé si j’avais un setFilter quelque part mais rien non plus.

Pour le calcul je sais que ce n’est pas optimal mais je ne le fais que pour les form.
Sinon c’est vrai que je pourrais la calculer dans le preSave de l’objet lié ! Je vais essayer

Ok j’ai compris, en fait le tuple chargé dans l’objet reste égal au dernier de la liste.

Dans un champ calculé, il ne faut pas utiliser les accesseurs de l’objet (car l’expression peut servir dans un contexte de liste) mais les bindings passés à l’interpréteur Rhino sont les suivants :

bindings.put(“obj”, obj);
bindings.put(“row”, row);
bindings.put(“parent”, obj.getParentObject());
bindings.put(“parentRefField”, obj.getParentObjectRefField());
bindings.put(“context”, context);
bindings.put(“grant”, obj.getGrant());

Donc pour avoir le “bon” rowId c’est row[0].

Simplicité pourrait forcer un obj.setValues(row, true) car c’est pas idéal ou intuitif d’utiliser row.
On va l’ajouter avant de calculer les champs.

Merci beaucoup avec row[0] ça fonctionne très bien.
J’ai regardé aussi pour mettre le calcul dans le presave pour faire moins coûteux, mais ça m’oblige à le mettre sur l’objet de liaison N,N et sur l’objet lié, en cas d’update, create, delete … ça me paraît compliqué à maintenir :-/

Ok

  • si le calcul est limité à un formulaire peu consulté ce n’est pas grave.
  • autre contrainte importante : on ne peut pas faire de recherche/tri sur un champ calculé non persistant, il faut alors écrire son propre filtre au preSearch sous forme de search-spec
  • donc oui parfois, il faut mieux persister la donnée = coder la mise à jour depuis chaque élément du calcul qui pourrait changer via un simple update(sql) dans une fonction commune appelée depuis certains hooks (ce n’est pas si terrible à faire).

Personnellement, je laisse les champs calculés non persistants pour des choses élémentaires sur le tuple pour la UI ou les exports (comme concaténer nom+prénom, ou une donnée volatile qui dépend de la date du jour = calculer l’âge d’un objet), mais dès qu’il y a une logique métier, je préfère avoir la donnée “sous le coude” en base au cas où elle servent un jour dans des règles fréquentes (hook, search-spec, contraintes…), comme par exemple le total d’une facture nécessaire tout le temps (crosstab, edition, recherche, tri…).

Sinon l’évolution pour avoir les valeurs “row” chargées dans l’objet au moment du calcul a été faite en V4+.

1 Like