Hibernatedia.apice.unibo.it/download/labs/04-hibernate-lab.pdf–interrogazione tramite query HQL,...

19
Laboratorio Hibernate Hibernate Laboratorio Programmazione di Applicazioni Data Intensive Laurea in Ingegneria e Scienze Informatiche DISI Università di Bologna, Cesena Giacomo Domeniconi, Gianluca Moro, Roberto Pasolini DISI Università di Bologna, Cesena [email protected]

Transcript of Hibernatedia.apice.unibo.it/download/labs/04-hibernate-lab.pdf–interrogazione tramite query HQL,...

Laboratorio Hibernate

Hibernate Laboratorio

Programmazione di Applicazioni Data Intensive

Laurea in Ingegneria e Scienze Informatiche DISI – Università di Bologna, Cesena

Giacomo Domeniconi, Gianluca Moro, Roberto Pasolini DISI Università di Bologna, Cesena

[email protected]

Laboratorio Hibernate

Riepilogo: Object-Relational Mapping

• Molte applicazioni sviluppate secondo il paradigma Object-Oriented gestiscono dati persistenti su database relazionali

• Object-Relational Mapping indica la soluzione per salvare e reperire oggetti su database relazionale, che risolve le differenze tra i due paradigmi (impedance mismatch) – identità dei dati, tipi di dato, navigabilità, …

• In genere a ciascuna classe model corrisponde una tabella sul DB e a ciascun oggetto persistente corrisponde una riga – Ad ogni proprietà di un oggetto bean corrisponde una colonna (o più)

– Le associazioni tra oggetti persistenti richiedono particolare attenzione

• Sono stati considerati tre approcci generali all’ORM – Il più semplice è integrare l’ORM in model e/o controller (forza bruta)

Applicazioni Data Intensive 2

Laboratorio Hibernate

Riepilogo: Data Access Object

• L’approccio DAO all’ORM prevede di incapsulare la logica di accesso al database in appositi Data Access Object – Il resto dell’applicazione usa i DAO per gestire oggetti persistenti

– Cambiamenti al database richiedono cambiamenti solo ai DAO

• I DAO forniscono metodi di alto livello per gestire i dati – Operazioni elementari su singoli oggetti (Create, Read, Update, Delete)

e altre (es. reperire tutte le categorie) a seconda delle necessità

• Per implementare i DAO si possono usare librerie per l’accesso diretto al database come JDBC – È in genere necessario specificare molte operazioni di basso livello,

secondo schemi ricorrenti per ciascun tipo di azione di alto livello

Applicazioni Data Intensive 3

Laboratorio Hibernate

Riepilogo: framework per la persistenza

• L’implementazione dei DAO basata su JDBC richiede grandi quantità di codice – Nella pratica ciò comporta tempi di sviluppo prolungati e alto rischio di

errori, nonostante le implementazioni seguano schemi ricorrenti

• I framework per la persistenza forniscono implementazioni generali e riusabili delle tipiche operazioni dei DAO – Gli sviluppatori non devono più implementare tutta la logica di accesso

al DB, ma solamente configurare il framework ed utilizzarne l’API

• Hibernate è un framework di persistenza in Java molto usato – implementazione open source dello standard JPA

Applicazioni Data Intensive 4

Laboratorio Hibernate

Caso di studio: DAO basato su Hibernate

• La nostra webapp definisce un’interfaccia generica GeneralDAO per l’accesso al DB

• Nella prima versione, questa era implementata in JDBC – Classe JDBCGeneralDAO in EStore-web.zip

• In questa esercitazione lavoreremo invece su un’implementazione del DAO basata su Hibernate – dichiarazione dei mapping entità-tabelle tramite annotazioni

– uso API di Hibernate (al posto di JDBC)

• L’interfaccia del DAO rimane valida → i controller dell’applicazione non sono cambiati dalla prima versione

Applicazioni Data Intensive 5

Laboratorio Hibernate

Laboratorio: progetto basato su Hibernate

• Si scarichi il file progetto EStore-Hibernate.zip – Se rimasto, eliminare dallo spazio di lavoro Eclipse la versione

precedente del progetto (clic destro sul progetto > Delete)

– Importare quindi il nuovo progetto (come fatto per il precedente)

• Hibernate è in parte già configurato per l’applicazione – Il file di configurazione hibernate.cfg.xml è completo

– La nuova versione del DAO è abbozzata in HibernateGeneralDAO (package it.unibo.dia.estore.dao.hibernate)

– La gestione di sessioni e transazioni in ciascuna richiesta è già implementata tramite il filtro HibernateRequestFilter

• La configurazione però non è completa: al momento non possiamo eseguire la webapp (si avrebbe un’eccezione)

Applicazioni Data Intensive 6

Laboratorio Hibernate

Riepilogo: sessioni e transazioni in Hibernate

• Una Configuration di Hibernate definisce il mapping tra classi e tabelle e altri aspetti (URL database, dialetto SQL, …)

• Da essa si crea una SessionFactory unica per tutta l’app

• Da questa si possono aprire sessioni contemporanee, ciascuna rappresenta un’unità di lavoro (operazioni correlate tra loro)

• Session fornisce i metodi per gestire oggetti persistenti

• In una sessione possono svolgersi più transazioni in sequenza

• In una webapp è comune aprire una sessione apposita (e una transazione) per ogni richiesta (pattern session-per-request) – Nella nostra webapp ciò è gestito automaticamente dal filtro servlet HibernateRequestFilter

Applicazioni Data Intensive 7

Laboratorio Hibernate

Riepilogo: dichiarazione del mapping tra classi e tabelle

• Per dichiarare il mapping tra classi e tabelle del DB, usiamo annotazioni JPA sulle classi e sui metodi get delle proprietà

• @Entity dichiara una classe entità – @Table(name = "…") indica il nome della tabella corrispondente

• Ogni proprietà della classe entità è persistente di default – @Column indica nome e altre proprietà della colonna (es. vincoli)

– @Transient marca le proprietà non persistenti

• @Id marca la proprietà corrispondente alla chiave primaria – @GeneratedValue indica come sono generate le chiavi

• @Embedded indica un oggetto incorporato – La classe dell’oggetto deve essere marcata @Embeddable

Applicazioni Data Intensive 8

Laboratorio Hibernate

Riepilogo: dichiarazione associazioni tra classi

• Un associazione sussiste quando una classe entità A ha una proprietà il cui tipo è un’altra entità B (o una collezione)

• Se bidirezionale, anche B dichiara una proprietà di tipo A – Bisogna distinguere lato diretto e inverso: modifiche alle associazioni

tra oggetti vanno effettuate sul lato diretto

– Il mapping va configurato sul lato diretto dell’associazione, mentre su quello inverso si inserisce un riferimento al diretto con mappedBy

• @ManyToOne e @OneToOne marcano proprietà il cui valore è un altro singolo oggetto persistente – @JoinColumn indica la colonna che ne contiene la chiave esterna

• @OneToMany e @ManyToMany marcano proprietà il cui valore è una collezione di altri oggetti persistenti – @JoinTable indica tabella di join e colonne con le chiavi dei due lati

Applicazioni Data Intensive 9

Laboratorio Hibernate

Esercizio 1: mapping tra classe e tabella

• Dichiarare nella classe User del model il mapping alla corrispondente tabella del database

• Annotare la classe come entità indicando il nome della tabella

• Indicare la proprietà id come identificatore degli oggetti, corrispondente alla colonna oid

• Specificare il mapping sulle altre proprietà, indicando il nome della colonna dove necessario – proprietà name → colonna username

– proprietà password → colonna password

– proprietà mailAddress → colonna email

• Mappare la proprietà orders come inversa di user in invoice, restituire gli ordini ordinati per data decrescente

Applicazioni Data Intensive 10

Laboratorio Hibernate

Riepilogo: lettura degli oggetti dal database

• L’interfaccia di Session fornisce vari metodi per reperire oggetti dal database – reperimento singoli oggetti per tipo e chiave primaria

– interrogazione tramite query HQL, API Criteria e query native SQL

• Per il reperimento di oggetti dall’ID sono dati due metodi, entrambi hanno per argomenti classe entità e ID – get recupera effettivamente l’oggetto dal database, verificando che

esista e restituendo null altrimenti

– load restituisce un riferimento ad un oggetto senza accedere al database (quindi senza verificare che esista)

Applicazioni Data Intensive 11

Laboratorio Hibernate

Esercizio 2: metodi DAO per reperire oggetti data la chiave primaria

• Ora che Il mapping delle classi alle tabelle è completo, usiamo l’API di Hibernate per reperire e salvare oggetti sul database

• Le API sono usate nella classe HibernateGeneralDAO, che implementa i metodi definiti in GeneralDAO

• Le implementazioni usano la Session disponibile nel campo privato hb (aperta automaticamente per ogni richiesta)

• Implementare tutti i metodi getEntità(int) che restituiscono un oggetto dal database dato l’ID

• Usare il metodo get per reperire gli oggetti e restituirne il risultato (anche se null)

Applicazioni Data Intensive 12

Laboratorio Hibernate

Riepilogo: Hibernate Query Language

• HQL è usato per esprimere query sugli oggetti salvati nel DB

• La sintassi riprende quella di SQL – elementi di base: [ SELECT proprietà ] FROM entità [ WHERE condizione ] [ ORDER BY proprietà ]

– solo FROM è obbligatorio (da solo restituisce tutti gli oggetti di un tipo)

• Da Session si può ottenere un oggetto Query – Query query = s.createQuery( "FROM User" );

• La query può contenere parametri di cui dichiarare i valori – s.createQuery( "FROM Invoice WHERE user=:who" ) .setParameter( "who", someUser );

• Su un oggetto Query si può invocare – list per ottenere una lista di risultati (in forma di Object)

– uniqueResult per ottenere direttamente un unico risultato atteso

Applicazioni Data Intensive 13

Laboratorio Hibernate

Esercizio 3: metodi DAO di interrogazione

• Implementare i metodi di lettura dati rimanenti nel DAO utilizzando opportune query HQL

• getUserByName restituisce l’utente col nome dato (o null se non esiste)

• getCategoriesTree restituisce gli oggetti Category di primo livello nella gerarchia delle categorie, ordinati per nome – Sono restituite le categorie senza parent, che contengono

transitivamente riferimenti a tutte le altre categorie

• searchProducts restituisce i prodotti il cui nome contiene la stringa di ricerca data, ordinati per nome – In SQL/HQL: x contiene “abc” ↔ x LIKE '%abc%‘

• Una volta implementati questi metodi, si può avviare ed usare la webapp, almeno dove non è prevista scrittura di dati su DB

14 Applicazioni Data Intensive

Laboratorio Hibernate

Riepilogo: Gestione oggetti persistenti

• Gli oggetti si gestiscono tramite i metodi di Session

• Ogni oggetto di una classe entità ha tre possibili stati – transitorio: non gestito da Hibernate, non corrisponde ad una riga DB

– persistente: gestito da una sessione, corrisponde ad una riga sul DB

– scollegato: precedentemente gestito da una sessione poi chiusa

• Un oggetto persistente si può modicare con i metodi set – Se scollegato, va associato a nuova sessione con update o merge

• Un oggetto transitorio si salva nel DB con persist o save – save genera e restituisce l’identificatore assegnato all’oggetto

• Con delete si elimina un oggetto dal DB

• I cambiamenti si scaricano dalla cache sul DB con flush – Di default flush è eseguito in automatico al commit delle transazioni

Applicazioni Data Intensive 15

Laboratorio Hibernate

Esercizio 4: metodi DAO di scrittura

• Implementare il metodo insertInvoice che salva un nuovo ordine nel database e restituisce l’ID assegnatoli – I dettagli dell’ordine (oggetti InvoiceEntry) vanno aggiunti alla

collezione entries dell’oggetto Invoice: sono salvati in cascata

• Implementare il metodo updateReview che aggiorna la recensione (Review) associata ad una InvoiceEntry con ID dato – Recuperare un riferimento alla InvoiceEntry e aggiornarla

• Non è necessario usare transazioni e/o eseguire il flush della sessione: è tutto gestito da HibernateRequestFilter

• Dopo aver implementato questi metodi, l’intera webapp dovrebbe essere funzionante

Applicazioni Data Intensive 16

Laboratorio Hibernate

Riepilogo: Paginazione di grandi collezioni

• Nelle webapp, è comune dividere in pagine di dimensione fissa liste di elementi (es. prodotti) potenzialmente grandi – Reperire l’intera lista sarebbe gravoso per server, rete e client

– Ogni pagina spesso presenta link alle altre e indica il totale di elementi

• Sulle Query Hibernate si possono limitare i dati da reperire – setFirstResult taglia i primi n oggetti dai risultati

– setMaxResults imposta il numero massimo di oggetti da reperire

– Fissati N oggetti/pagina, la pagina p di risultati di una query q si ha con q.setMaxResults(N).setFirstResult(N*p).list()

• Queste funzionalità hanno limiti, che richiedono accorgimenti – disponibili solo su query, non su liste di oggetti incorporati/associati

– la lista da dividere in pagine deve avere un ordine fisso

– il numero totale di oggetti non è dato, serve una query aggiuntiva

Applicazioni Data Intensive 17

Laboratorio Hibernate

Supporto alla paginazione nella webapp

• La paginazione è utile in diversi contesti nella nostra webapp – risultati ricerca prodotti, prodotti per categoria, recensioni di prodotto

• Usiamo quindi un supporto generico valido in ogni contesto

• La classe ListPage incapsula una pagina di elementi e le informazioni su quantità di pagine e di elementi

• Il tag JSTL personalizzato pageinfo mostra informazioni e link di navigazione tra pagine per un oggetto ListPage dato – url indica l’URL tipo da usare per navigare tra le pagine

• ListPage definisce un costruttore con parametri: – List degli elementi che compongono la pagina rappresentata

– numero della pagina (contando da 0)

– numero di elementi per pagina

– numero totale di elementi nella collezione

Applicazioni Data Intensive 18

Laboratorio Hibernate

Esercizio 5: reperimento di dati in pagine

• Modificare il metodo searchProductsPaged in modo che restituisca un oggetto ListPage rappresentante un’unica pagina di prodotti risultanti da una ricerca – La versione attuale usa il metodo searchProducts per ottenere

tutti i risultati e li restituisce come una pagina unica

• Il metodo accetta come parametri: – la stringa di ricerca (query, come in searchProducts)

– il numero di elementi per pagina (itemsPerPage)

– il numero della pagina da reperire, contando da 0 (page)

• Testare il metodo su ricerche con molti risultati, ad es. “Star” – il numero di risultati per pagina si può cambiare in SearchServlet

Applicazioni Data Intensive 19