La data entity: una vista, non una tabella
Il primo concetto da fissare è che una data entity non è una tabella. È un elemento AOT che espone una vista denormalizzata su una o più tabelle sottostanti, con i suoi campi, le sue relazioni e la sua logica di validazione. Dove il modello fisico spezza un cliente fra CustTable, DirPartyTable e le tabelle degli indirizzi, l’entity ricompone il tutto in un’unica superficie piatta, comprensibile a un sistema esterno che non conosce — e non deve conoscere — il modello relazionale interno.
Questa superficie unica serve due scopi che l’esame tiene volutamente vicini per confonderti. Da un lato l’import/export massivo tramite il Data management framework; dall’altro l’esposizione via OData per l’accesso record per record. È la stessa entity, ma i due usi hanno prerequisiti diversi: perché un’entity sia consumabile via OData deve essere marcata come pubblica e avere un nome di collection pubblico, mentre per il solo import/export questo non serve. Un’entity progettata bene per il DMF non è automaticamente un endpoint OData.
OData, Batch OData e custom service
OData è il canale sincrono per operazioni CRUD sui record esposti dalle entity pubbliche: leggi, crei, aggiorni, filtri e paghi il prezzo di una chiamata HTTP per operazione. Va benissimo per volumi bassi e per scenari interattivi, dove il chiamante ha bisogno della risposta immediata e del record aggiornato. Diventa un problema quando le operazioni si moltiplicano: centinaia di chiamate significano centinaia di round trip, con la latenza di rete che domina il tempo totale.
Qui entra il Batch OData API, che consente di raggruppare più operazioni in un’unica richiesta HTTP. Il guadagno non è nel database ma nella rete: meno round trip, throughput migliore a parità di logica. Resta comunque un canale sincrono e non è il sostituto di un’importazione massiva: per milioni di righe la risposta corretta è il DMF, non OData in batch.
I custom service rispondono a un bisogno diverso. OData espone dati; un custom service espone logica applicativa. Se l’esterno deve invocare un’operazione — validare un ordine, calcolare un prezzo, far scattare un processo — con parametri in ingresso e un risultato strutturato che non corrisponde a nessuna riga di tabella, il custom service scritto in X++ è la scelta giusta. Il criterio è secco: dati anagrafici o transazionali già modellati come entity → OData; verbo applicativo con contratto proprio → custom service.
Il Data management framework
Il Data management framework è il motore dei carichi massivi. Si lavora per data project (import o export), in cui si scelgono le entity coinvolte, il formato sorgente (CSV, Excel, XML e altri) e la mappatura dei campi fra file sorgente, staging table e tabella target. La staging è il punto chiave: i dati atterrano prima lì, dove passano validazione e trasformazione, e le righe in errore restano isolate e correggibili senza rilanciare l’intero carico. Solo dal passaggio staging → target il dato entra davvero nell’applicazione, attraversando la logica dell’entity. I template e i data project riutilizzabili servono a rendere ripetibile la configurazione fra ambienti.
Il DMF lavora naturalmente in asincrono, appoggiandosi al batch framework per i job lunghi e ricorrenti: è la modalità corretta quando il volume è alto e la latenza non è un requisito.
Sincrono, asincrono e change tracking
Il criterio di scelta si riduce a due domande. Il chiamante ha bisogno della risposta subito? Allora sincrono: OData o custom service. Il volume è grande e la tolleranza al ritardo alta? Allora asincrono: DMF con data project schedulati nel batch framework. Un’integrazione ad alto volume forzata su OData è un errore di design tipico, così come lo è usare il DMF per una lookup interattiva.
Per gli export ricorrenti resta il problema di non riesportare ogni volta l’intero dataset. La risposta è il change tracking, che si abilita sull’entity e permette export incrementali: solo i record modificati dall’ultima esecuzione. Va abilitato consapevolmente, perché il tracking ha un costo, e va ricordato che un export configurato come full ignora comunque il delta.
Trappole tipiche d’esame
- Milioni di righe da caricare da file esterni → Data management framework asincrono, non OData: lo scenario ti mette davanti un’integrazione ad alto volume e ti propone OData (magari in batch) come opzione. Il Batch OData API riduce i round trip, non trasforma un canale sincrono in uno strumento di bulk load.
- L’entity funziona per l’import ma l’endpoint REST dà 404 → entity non pubblica: import/export via DMF ed esposizione OData hanno prerequisiti diversi. Serve che l’entity sia marcata come pubblica con il relativo nome di collection.
- Serve invocare un’operazione con parametri custom → custom service, non OData: se il contratto in ingresso e in uscita non corrisponde a un record di un’entity, forzare la logica dentro un’entity è la risposta sbagliata.
- Righe rifiutate durante l’import → si correggono in staging, non si rilancia tutto: la staging table esiste proprio per isolare gli errori. La risposta che propone di ricaricare l’intero file è quella scartabile.
- Export notturno che deve portare solo i record cambiati → change tracking sull’entity: filtrare per data di modifica a mano, o riesportare tutto e deduplicare a valle, sono le distrazioni classiche.
- Nuovo campo su una tabella standard da esporre all’esterno → table extension più estensione dell’entity, mai overlayering: la trappola mescola integrazione e customizzazione; la strada supportata resta l’extension.