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 globaliSet(varUtente, User().FullName): visibili in tutta l’app, adatte a valori condivisi tra schermate.
  • Variabili di contestoUpdateContext({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: eliminano Set sparsi in OnStart e 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 aggregati Sum, 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 Filter ridondanti dentro proprietà che si rivalutano di continuo.

  • Caricamento parallelo con Concurrent: raggruppa richieste indipendenti in OnStart/OnVisible così 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 su Screen.OnVisible così 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 OnStart pesante 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 funzione Len non è 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 Concurrent per eseguirli in parallelo, non tre ClearCollect in sequenza.
  • Scenario: l’app parte lentamente perché carica tutto in App.OnStart. → Sposta il caricamento su Screen.OnVisible con lazy loading, tenendo in OnStart solo l’essenziale.
  • Scenario: serve un valore calcolato (es. totale con IVA) usato in più punti, sempre aggiornato. → Definisci una named formula in App.Formulas invece di una variabile impostata con Set.
  • 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.