Mapping di Gerarchie con Hibernate (parte 2)

Nel precedente articolo Mapping di Gerarchie con Hibernate (parte 1) abbiamo parlato le strategie di mapping per le gerarchie MappingSuperclass e Single Table. In questo post proseguiamo descrivendo le rimanenti strategie Join Table e Table-Per-Class.

Join Table

Utilizzando tale strategia ogni classe della gerarchia è mappata in una tabella. Le diverse entità condividono una sola colonna, l’identificatore id dichiarato nella classe Asset, che è utilizzata come campo di join tra le tabelle per recuperare il record completo.

L’implementazione della strategia si ottiene valorizzando opportunamente l’annotazione @Inheritance sulla classe Asset.

Eseguiamo il main() associato al modulo ed analizziamo l’output generato con tale strategia:

Innanzitutto è droppato il database e vengono rigenerate le tabelle Asset, Laptop e MobilePhone. Come ci si aspettava tutte le tabella hanno la colonna id di tipo primary key ed inoltre è generato un vincolo di foreign key tra le colonne id di Laptop e MobilePhone, e la colonna id di Asset.

Il salvataggio di 4 record genera in realtà 8 inserimenti. Per ogni record infatti è generata una riga sia sulla tabella Asset che sulla tabella specifica del tipo di asset.

Per il recupero dei record questa volta utilizziamo una query HQL che esegue una select sulla tabella Asset.

La query generata da Hibernate e ben più complicata delle precedenti in quanto deve essere eseguita una join che coinvolge tutte le tabelle.

In generale il numero di join necessarie aumenta con il livello della gerarchia dove si intende eseguire la query, in quanto devono essere coinvolte tutte le tabelle discendenti rispetto al punto di select. Ovviamente la join non è necessaria se si esegue la select direttamente sulle entità figli: Laptop o MobilePhone.

Possiamo quindi concludere dicendo che con tale strategia le performance potrebbero essere scadenti nel caso di recupero di un gran numero di record con query che coinvolgono le classi gerarchicamente più alte.

Table Per Class

Con questo tipo di strategia è generata una tabella per ogni classe della gerarchia in cui sono presenti tutte le colonne necessarie a mappare tutte le proprietà ereditate. Molto simile alla strategia MappedSuperclass con la differenza che è generata una tabella anche per la classe genitrice. Inoltre rispetto alla strategia Join Table non esiste relazione tra l’entità padre e le figlie, al punto che è possibile inserire un record Asset che non è né un Laptop né un MobilePhone.

Eseguiamo il main() associato al modulo ed analizziamo l’output generato con tale strategia:

Come ci aspettavamo sono generate tre tabelle, una per Asset con la sola colonna id, una per Laptop e MobilePhone in cui è presente anche la colonna id ereditata. Inoltre non ci è alcuna foreign key tra le tabelle figlie e la padre.

In questo caso oltre ai 4 record, due per tipologia di asset, inseriamo anche un record generico sulla tabella Asset.

Per il recupero dei record valgono considerazioni molto simili a quell fatte per la strategia Join Table. In questo caso però la query eseguita sulla classe Asset comporta la generazione un una serie di UNION tra tutte le entità della gerarchia.

Codice Sorgente

Il codice sorgente completo con tutti gli esempi di questo e del precedente articolo è scaricabile qui hibernate.