Power Fx: formule, variabili e collections
Power Fx è il linguaggio dichiarativo delle canvas app: si scrive per espressioni, come in Excel, e il motore ricalcola automaticamente quando cambia un valore da cui una formula dipende. Da sviluppatore devi conoscere i tre modi di conservare lo stato, perché la scelta ha impatto diretto su performance e manutenibilità:
- Variabili globali —
Set(varUtente, User().FullName): visibili in tutta l’app, adatte a valori condivisi tra schermate. - Variabili di contesto —
UpdateContext({mostraPannello: true}): limitate alla singola screen, ideali per stato locale come toggle o flag di UI. - Named formulas (sezione
App.Formulas) — es.PrezzoIvato = Prezzo * 1.22;: valori calcolati, immutabili e sempre aggiornati, valutati “on demand”. Vanno preferite alle variabili quando il valore è derivabile: eliminanoSetsparsi inOnStarte riducono lo stato mutabile.
Le collections sono tabelle in memoria sul client: ClearCollect(colProdotti, Products) scarica i dati una volta e poi li riusi senza ulteriori round-trip. Usa Patch, Collect, Remove per manipolarle. Attenzione però: una collection è una copia locale, quindi va rinfrescata quando i dati sorgente cambiano, e caricare interi dataset “per comodità” è spesso un anti-pattern.
Delegation verso Dataverse
La delegation è il meccanismo per cui Power Fx delega l’elaborazione della query al data source invece di scaricare le righe e filtrarle sul client. Con Dataverse questo significa tradurre Filter, LookUp, Sort in una query eseguita server-side, così l’app riceve solo le righe che servono.
Funzioni e operatori delegabili con Dataverse includono:
- Funzioni:
Filter,LookUp,Search,Sort,SortByColumns, e gli aggregatiSum,Average,Min,Max,CountRows. - Operatori:
=,<>,<,<=,>,>=,And/&&,Or/||,Not/!,in,StartsWith.
Sono tipicamente non delegabili le espressioni che manipolano il valore dentro il predicato — Lower(), Len(), Left(), Mid() applicate alla colonna filtrata — o l’ordinamento su una formula anziché su una colonna. Nel dubbio, il Power Fx Studio mostra un avviso di delegation (triangolo giallo / sottolineatura blu) sul punto esatto della formula.
L’effetto del delegation limit
Quando una query non è delegabile, Power Fx la esegue localmente ma solo sulle prime righe scaricate: il delegation limit di default è 500 righe, configurabile fino a 2000 in Settings → General → Data row limit. Il problema è insidioso perché non genera errori: se la tabella ha 10.000 record e il filtro non è delegabile, l’app valuta il predicato solo sulle prime 500 righe recuperate, restituendo risultati parziali e silenziosi. L’utente vede un elenco plausibile ma incompleto, e il bug emerge solo su dataset grandi.
Best practice di performance
-
Riduci le chiamate al data source: carica una volta in collection ciò che riusi, evita
Filterridondanti dentro proprietà che si rivalutano di continuo. -
Caricamento parallelo con
Concurrent: raggruppa richieste indipendenti inOnStart/OnVisiblecosì partono in parallelo invece che in sequenza.Concurrent( ClearCollect(colClienti, Accounts), ClearCollect(colProdotti, Products) ) -
Lazy loading: non caricare tutto in
App.OnStart; sposta il caricamento suScreen.OnVisiblecosì l’avvio dell’app resta rapido e i dati vengono presi solo quando servono. -
Scrivi sempre formule delegabili: preferisci operatori nativi, sposta la logica non delegabile fuori dal predicato, e verifica di non superare mai il delegation limit su tabelle in crescita.
-
Limita
OnStartpesante e usa named formulas per i calcoli derivati, evitando ricalcoli manuali.
Trappole tipiche d’esame
- Scenario: una Gallery su una tabella Dataverse da 8.000 righe filtra con
Filter(Tabella, Len(Codice) = 5)e mostra pochi risultati. → La funzioneLennon è delegabile: la query scarica solo 500 righe e il resto viene ignorato in silenzio; riscrivi il filtro con operatori delegabili o filtra su una colonna dedicata. - Scenario: devi caricare tre dataset indipendenti all’apertura minimizzando il tempo. → Usa
Concurrentper eseguirli in parallelo, non treClearCollectin sequenza. - Scenario: l’app parte lentamente perché carica tutto in
App.OnStart. → Sposta il caricamento suScreen.OnVisiblecon lazy loading, tenendo inOnStartsolo l’essenziale. - Scenario: serve un valore calcolato (es. totale con IVA) usato in più punti, sempre aggiornato. → Definisci una named formula in
App.Formulasinvece di una variabile impostata conSet. - Scenario: il team chiede di “alzare il limite” per far tornare i conteggi. → Aumentare il data row limit fino a 2000 è un palliativo; la risposta corretta è rendere la query delegabile, perché oltre 2000 righe il problema si ripresenta.