## Guida: risoluzione tabelle di decodifica tramite Lookup Resolvers

Questa guida descrive l'utilizzo della feature denominata LookupResolver per la risoluzione automatica delle associazioni N-1, tipicamente utilizzate nel caso di tabelle di decodifica.

### Introduzione

Il LookupResolver è un costrutto associabile ad ogni DataAccessObject. Come facilmente intuibile dal nome, esso permette di risolvere i lookup associati ad una determinata tabella. Per lookup intendiamo il reperimento di elementi informativi associati in relazione N-1, spesso descritti come tabelle di decodifica. Tipicamente il lookup coinvolge almeno due tabelle:

1. La tabella principale che referenzia la tabella di decodifica tramite una foreign-key
2. La tabella di decodifica, contenente informazioni aggiuntive (es. descrizione) oltre alla primary-key che permette alle altre tabelle principali di effettuare il collegamento.

Un esempio di tale struttura può essere quello relativo alla struttura relazionale descritta di seguito.

- la tabella ANAGRAFICA contiene quattro colonne:
  - NOME (varchar2) : colonna informativa
  - COGNOME (varchar2): colonna informativa
  - CODICE_PROVINCIA (number): colonna con vincolo di chiave esterna verso la chiave primaria ID_PROVINCIA della tabella PROVINCIE
  - CODICE_REGIONE (number): colonna con vincolo di chiave esterna verso la chiave primaria ID_REGIONE della tabella REGIONI
- la tabella PROVINCIE contiene due colonne:
  - ID_PROVINCIA (number): chiave primaria
  - DESCRIZIONE_PROVINCIA (varchar2): colonna informativa
- la tabella REGIONI contiene due colonne:
  - ID_REGIONE (number): chiave primaria
  - DESCRIZIONE_REGIONE (varchar2): colonna informativa

Nell'utilizzo classico, (ovvero senza l'impiego del LookupResolver), quando si utilizza il DAO per accedere ai dati della tabella ANAGRAFICA, si ottiene un risultato costitutito da uno o più DTO i cui campi corrispondono (in nome e in tipo) alle colonne della tabella ANAGRAFICA.

Qualora ci fosse la necessità di recuperare le informazioni estese dei due campi, ovvero DESCRIZIONE_PROVINCIA e DESCRIZIONE_REGIONE, ad esempio perchè è necessario visualizzare a video la regione di residenza, nella modalità tradizionale è necessario effettuare altri due accessi in chiave primaria alle tabelle di decodifica, rispettivamente PROVINCIE e REGIONI. E' però possibile utilizzare il LookupResolver per:

- fare in modo che i DTO contengano dei campi strutturati corrispondenti ai DTO relativi alle tabelle in foreign-key
- fare in modo che il DAO della tabella principale possa automaticamente risolvere le associazioni di decodifica ricostruendo l'oggetto completo

### Utilizzo della funzionalità

Supponiamo di avere a disposizione il modello dello schema relazionale dell'esempio e un modello di accesso ai dati nel quale verranno inseriri i vari DAO. Definiamo pertanto tre DAO: anagrafica, provincie, regioni.

I Lookup Resolver sono elementi associabili a ciascun Data Access Object. Tutti i LookupResolver di un DAO devono essere contenuti in un elemento di tipo LookupResolvers, a sua volta contenuto nel DataAccessObject. Nel caso in esame, si suppone di dover effettuare la lookup sulle tabelle PROVINCIE e REGIONI, pertanto è necessario definire due resolver associati al dao angrafica e alle due foreign key che dalla tabella ANAGRAFICA puntano alle due tabelle PROVINCIE e REGIONI.

Ogni resolver si compone di tre properties specifiche:

- Foreign Key: rappresenta il riferimento alla chiave esterna della tabella master (ANAGRAFICA nell'esempio) che permette di reperire il record corretto della tabella associata (PROVINCIE o REGIONI nell'esempio).
- Supplier DAO: il riferimento al data access object che verrà utilizzato per risolvere la lookup.
- Name: nome simbolico (opzionale) che verrà utilizzato (se presente) come nome della proprietà JAVA associata all'oggetto risolto. Se non specificato tale property avrà invece il nome della foreign key stessa.

Questa configurazione fa intravedere il principio secondo il quale avviene effettivamente la risoluzione del lookup, ovvero mediante delega da parte del DAO principale ai DAO associati alle tabelle di lookup.

Nel caso dell'esempio avremo pertanto:

- resolver su tabella PROVINCIE:
  - Name: null (ad esempio)
  - Foreign Key: fk_ANAGRAFICA_FK_PROVINCIA
  - Supplier DAO: Data Access Object provincie
- resolver per la tabella REGIONI:
  - Name: null (ad esempio)
  - Foreign Key: fk_ANAGRAFICA_FK_REGIONI
  - Supplier DAO: Data Access Object regioni

Si osservi che, operativamente, durante la modellazione del LookupResolver, una volta selezionata la foreign key, le possibili scelte circa il Supplier DAO si restringono ai DAO relativi alla tabella effettivamente referenziata dalla foreign-key selezionata appena prima. E' pertanto importante rispettare l'ordine di selezione degli elementi nel modello.

Poichè la risoluzione delle decodifiche avviene tramite delega ai dao supplier è necessario che ciascun Supplier DAO definito nei vari resolver presenti il finder "findByPK". E' importante altresì notare che tutti i passi appena elencati non differiscono nel caso di foreign key composite.

### Note sul codice generato

A fronte dell'utilizzo di un LookupProvider si ottiene un codice dei DAO leggermente differente da quello ottenuto nel caso in cui non si utilizzino i LookupResolver:

- Il DTO della tabella master (ANAGRAFICA) contiene, oltre ai campi relativi alle colonne chiave primaria e i campi informativi della tabella stessa, anche dei campi strutturati del tipo del DTO delle tabelle referenziate. Ad esempio il DTO Anagrafica conterrà i seguenti campi:
  - String nome
  - String cognome
  - Provincia fkAnagraficaFkProvincia
  - Regione fkAnagraficaFkRegione
- Il DAO di Anagrafica referenzierà tramite spring i DAO di Provincie e Regioni
- Il RowMapper accederà ai DAO supplier per ricostruire gli attributi "risolti", effettuando una `findByPrimaryKey` su tali DAO.
- La classe Example relativa alla tabella principale (ed utilizzata nella modalit` di query denominata query by example - QBE) contiene, in corrispondenza ai campi risolti tramite LookupProvider, un oggetto del tipo dell'Example corrispondente alla tabella risolta (Es. AnagraficaExample contiene un campo di tipo RegioneExample).

### Effetto sulle operazioni di scrittura (insert/update)

La presenza di un LookupResolver non ha particolari effetti sulle operazioni di scrittura (insert/update), a parte il fatto che durante le operazioni di insert e update vengono utilizzati solo i valori di primo livello, ossia:

- i campi chiave della tabella in oggetto
- i campi descrittivi della tabella in oggetto
- i campi FK per cui non esista un LookupResolver
- i campi chiave dei campi strutturati derivanti dalla definizione di un LookupResolver (es. il campo codProvincia del DTO Provincia contenuto nel DTO Anagrafica)

### Effetto sulle operazioni di delete

La presenza di un LookupResolver non modifica il comportamento delle operazioni di delete

### Effetto sulle operazioni di lettura (finder di vario genere)

Il LookupResolver è specificamente studiato per le operazioni di lettura. L'effetto principale è quello già ampiamente descritto e consiste nella differente profondità di popolamento dei DTO di risposta alla query. In particolare è però importante notare come il meccanismo di strutturazione può essere sfruttato anche nella modalità QBE.

#### Limitazioni

Attualmente sussistono alcune limitazioni derivanti dall'utilizzo del LookupResolver.

- E' possibile gestire con un LookupResolver solo foreign-key che non appartengano a loro volta a primary key della tabella principale.
- Non è possibile definire strutture cicliche di LookupResolver
- Nella modalità di query denominata query-by-example non è possibile esplicitare un criterio di filtro su un campo non chiave di una tabella risolta (ad esempio in un `findByExamples` relativo alla tabella Anagrafica, non sarà possibile utilizzare un esempio che contenga, per esempio, un filtro sul nome della regione, ma solo sul suo identificativo)

### Ulteriori note

Il meccanismo di LookupResolver spesso è utilizzato per risolvere il lookup di tabelle di decodifica: questa tipologia di tabelle spesso possiedono la caratteristica di presentare una alta stabilità per quanto riguarda l'insieme dei record (es. le provincie, i comuni, ...). In queste condizioni risulta pertanto molto utile abbinare al meccanismo del LookupResolver il meccanismo di DAO cache relativamente ai DAO delle tabelle di decodifica. In questo modo l'operazione di risoluzione del lookup avviene in memoria senza accesso al DB, con un evidente miglioramento delle prestazioni. Per impostare la cache su un DAO è necessario definire i suoi dati come ALMOST_STABLE_DATA e questa operazione può essere effettuata agendo sul modello, nelle property dell'oggetto DataAccessObject.

### Approfondimenti

Esempi pratici dell'utilizzo del LookupResolver si possono trovare all'interno della Reference Application MDD.