12 Hibernate3 Associazioni polimorfiche

Hibernate
Associazioni
polimorfiche
Dott. Doria Mauro
[email protected]
[email protected]
Associazioni polimorfiche
Una delle caratteristiche fondamentali di un ORM framework è la
capacità di supportare le associazioni polimorfiche e le query
polimorfiche.
Una associazione polimorfica è una associazione tra una classe
concreta e un’altra entità la quale può essere:
–
–
–
Una superclasse
Una classe astratta
Una interfaccia
(dipende da come è stata mappata la generalizzazione)
2
Gran parte del lavoro è stato effettuato mappando la
generalizzazione tra le classi; il mapping delle associazioni
polimorfiche è relativamente semplice.
[email protected]
Associazioni polimorfiche
Vediamo un primo esempio: Un user possiede un sistema di
pagamento; questio può essere di diverso tipo, ad esempio carta di
credito o bonifico bancario.
1
3
NOTA: User ha
due associazioni
polimorfiche con
BillingDetails
Quando si costruisce un oggetto user, si assegna polimorficamente un
oggetto di tipo BillingDetails. Nel rendere persistente l’oggetto user,
Hibernate provvede a creare l’associazione tra i redcord user e il record
corrispondente al BillingDetails scelto per l’user.
[email protected]
Associazioni polimorfiche
singoli valori
Iniziamo con il mappare all’associazione “default”
Il mapping della classe User sarà:
Superclasse interfaccia
o
classe
astratta.
Dipende dalle politiche
di
mapping
della
generalizzazione
<many-to-one name="defaultBillingDetails”
class="BillingDetails“
cascade=“all”
column="DEFAULT_BILLING_DETAILS_ID"/>
4
Tenendo conto che la classe BillingDetails è stata mappata con
le sue sottoclassi, non vi solo altre cose da fare. Di seguito, come
rendere persistente un user:
User unUser = new User("Alvaro", "Vitali");
CreditCard unaCc = new CreditCard("pippo", "10", 12,2009);
unUser.setDefaultBillingDetails(cc);
session.save(unUser);
[email protected]
Associazioni polimorfiche
singoli valori
Hibernate gestisce le associazioni polimorfiche allo scopo di
allineare la logica del polimorfismo con quella del mapping con la
base dati.
Vediamo cosa significa questo con un esempio:
//si recupera una istanza user dal DB
User user = (User) session.get(User.class, userId);
// si invoca il metodo pay() sull’istanza restituita
BillingDetails bill = user.getDefaultBillingDetails();
bill.pay();
5
Hibernate
mappa
l’oggetto user con il
suo concreto tipo di
pagamento sul DB
Il metodo user.getDefaultBillingDetails() restituisce un oggetto
concreto di tipo BillingDetails (CreditCard o BankAccount) ma
viene assegnato al tipo generico BillingDetails. Invocando il
metodo pay si attiva il polimorfismo java.
[email protected]
Associazioni polimorfiche
lazy-loading
Attenzione:
Hibernate attiva il lazy-loading di default (lazy = true); questo
comporta la possibile presenza di una classe proxy al posto della
classe concreta di tipo BillingDetails. Quindi, il seguente codice
potrebbe portare ad una BadCastException
Instanza proxy
User unUser = (User) session.get(User.class, userid);
BillingDetails bd = unUser.getDefaultBillingDetails();
System.out.println( bd instanceof CreditCard ); // se stampa "false"
CreditCard unaCc = (CreditCard) bd; // ClassCastException!
In ogni caso, nella maggior parte dei casi, non c’è motivo di fare un
cast alla classe specifica
6
[email protected]
Associazioni polimorfiche
collections polimorfiche
Vediamo adesso l’associazione bidirezionale uno-a-molti tra
User e BillingDetails.
Aggiungiamo nel mapping della classe Billing Details:
<many-to-one name="user"
class="User"
column="USER_ID"/>
7
Mentre per la classe User:
<set name="billingDetails“ inverse="true">
<key column="USER_ID"/>
<one-to-many class="BillingDetails"/>
</set>
[email protected]
Associazioni polimorfiche
collections polimorfiche
Di seguito un utilizzo polimorfico dell’user: invocazione del
metodo pay() su tutti gli oggetti di tipo BillingDetails di un user,
qualunque siano le classi che concretizzano BillingDetails.
User unUser = (User) session.get(User.class, userId);
for( BillingDetails bd : unUser.getBillingDetails() ) {
// si invoca il metodo pay() di BankAccount o di CreditCard
bd.pay(totale);
}
8
[email protected]
Associazioni polimorfiche
collections polimorfiche: mapping di tipo uno
Sono previste delle operazioni aggiuntive per il mapping della
generalizzazione fatta con le prime due strategie (normale e <unionsubcalss>)
Primo caso, mapping di tipo uno (normale) :
–
9
non abbiamo necessariamente una tabella per la classe BillingDetails e
quindi dobbiamo aggiungere una chiave esterna a mano nelle tabelle
concrete.
Se la superclasse BillingDetails è concreta, nel suo mapping dobbiamo
aggiungere una chiave esterna verso user.
<many-to-one name="user"
column="USER_ID"
class="User"/>
[email protected]
Associazioni polimorfiche
collections polimorfiche: mapping di tipo uno
10
Se la superclasse BillingDetails è astratta o è una interfaccia,
non abbiamo una tabella in corrispondenza di BillingDetails.
In questo caso è necessaria una configurazione aggiuntiva per il
mapping di User:
<any name="defaultBillingDetails"
id-type="long"
meta-type="string">
<meta-value value="CREDIT_CARD" class="CreditCard"/>
<meta-value value="BANK_ACCOUNT“ class="BankAccount"/>
<column name="DEFAULT_BILLING_DETAILS_TYPE"/>
<column name="DEFAULT_BILLING_DETAILS_ID"/>
</any>
[email protected]
Associazioni polimorfiche
collections polimorfiche: mapping di tipo due
Secondo caso, mapping di tipo due (union-subclass) :
–
non abbiamo necessariamente una tabella per la classe BillingDetails
(dipende dall’attributo abstract); in ogni caso dobbiamo aggiungere una
chiave esterna a mano nelle tabelle concrete.
Indipendentemente
dal valore di
abstract, viene
aggiunta una
colonna nuova in
ogni tabella
concreta
11
<class name="BillingDetails" abstract="true">
<id name="id" column="BILLING_DETAILS_ID" .../>
<property .../>
<many-to-one name="user“ column="USER_ID“ class="User"/>
<union-subclass name="CreditCard" table="CREDIT_CARD">
<property .../>
</union-subclass>
<union-subclass name="BankAccount" table="BANK_ACCOUNT">
<property .../>
</union-subclass>
</class>
[email protected]
Domande?
Collection polimorfiche
<any>
Associazioni
polimorfiche
generalizzazione
polimorfismo
proxy
<union-subclass>
12
Polimorfismo