Cosa fare se volessimo riutilizzare la classe Address
all'interno di diverse Entities in cui le tabelle associate contengono gli stessi campi ma con nomi relazionali diversi? Immaginiamo di avere un Entity Order che contiene gli stessi campi di Address per l'indirizzo di spedizione, ma con nomi sulla tabella ORDER_TABLE
come a STREET_SHIPMENT
, CITY_SHIPMENT
, STATE_SHIPMENT
. Come possiamo utilizzare Address
come classe Embedded nell'Entity Order?
La soluzione fornita da JPA risiede nell'utilizzo dell'annotation @AttributeOverrides
che consente di ridefinire di volta in volta il nome della colonna associata.
@Entity
@Table(name="ORDER_TABLE")
public class Order {
......
private Address address;
......
@Embedded
@AttributeOverrides({
@AttributeOverride(name="street", column=@Column(name="STREET_SHIPMENT")),
@AttributeOverride(name="city", column=@Column(name="CITY_SHIPMENT")),
@AttributeOverride(name="state", column=@Column(name="STATE_SHIPMENT"))
})
public Address getAddress(){
}
.....
}
Abbiamo mostrato come utilizzando l'annotation @Id
sia possibile specificare un campo di un Entity come identificativo dell'Entity stessa. I valori sul tale campo vengono generati automaticamente attraverso l'uso di una di tre possibili strategie:
- Identity generator
- Sequence generator
- Table generator
Tutte queste strategie fanno uso dell'annotation @GeneratedValue
; in tali situazioni un vincolo Identity può essere utilizzato per la generazione dei valori della chiave primaria. Tutto ciò che dobbiamo fare a livello di codice è applicare @GeneratedValue
sul metodo get annotato con @Id
:
@Entity
@Table(name="CUSTOMER_TABLE")
public class Customer{
....
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="CUSTOMER_ID")
public long getId(){....}
....
}
Il codice assume che un vincolo Identity sia definito sulla colonna CUSTOMER_ID
in CUSTOMER_TABLE
. Il valore sul campo chiave dell'Entity sarà disponibile dopo l'operazione di persistenza che salva un'istanza dell'Entity sul database.
Per utilizzare un Sequence Generator, dobbiamo per prima cosa definire una sequence a livello di database
da collegare al campo chiave dell'Entity. Costruiremo ed eseguiremo preliminarmente un'istruzione
SQL del tipo:
CREATE SEQUENCE CUSTOMER_SEQUENCE START WITH 1 INCREMENT BY 10;
Successivamente definiamo il Sequence Generator a livello di Entity utilizzando @SequenceGenerator
e
specifichiamo l'uso del sequence generator con l'attributo generator di @GeneratedValue
che punta
al nome del generatore
@Entity
@Table(name="CUSTOMER_TABLE")
@SequenceGenerator(name="CUSTOMER_SEQUENCE_GEN",sequenceName="CUSTOMER_SEQUENCE")
public class Customer {
....
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="CUSTOMER_SEQUENCE_GEN")
@Column(name="CUSTOMER_ID")
public long getId(){..}
....
}
Esaminiamo ora la strategia Table Generator. In questa caso si utilizza una tabella che memorizza
nomi di sequence e valori associati:
CREATE TABLE SEQUENCE_TABLE (
SEQUENCE_NAME VARCHAR NOT NULL,
SEQUENCE_VALUE NUMBER NOT NULL,
PRIMARY KEY (SEQUENCE_NAME)
)
Il passo successivo è quello di inserire un'entry per il campo chiave id
dell'Entity Customer:
INSERT INTO SEQUENCE_TABLE(SEQUENCE_NAME,SEQUENCE_VALUE) VALUES('CUSTOMER_SEQUENCE',1)
Possiamo vedere questi due step come equivalenti al singolo step del Sequence Generator. Anche se la strategia
Table Generator è più complessa ha il vantaggio che la stessa Sequence Table ospita una molteplicità di sequence
fornendo un controllo centralizzato sulla generazione delle chiavi primarie. A livello di codice l'uso di un Table
generator è molto simile ad un Sequence Generator:
@Entity
@Table(name="CUSTOMER_TABLE")
@TableGenerator(name="TABLE_GENERATOR",
table="SEQUENCE_TABLE",
pkColumnName="SEQUENCE_NAME",
valueColumnName="SEQUENCE_VALUE",
pkColumnValue="CUSTOMER_SEQUENCE")
public class Customer {
....
@Id
@GeneratedValue(strategy=GenerationType.TABLE,generator="TABLE_GENERATOR")
@Column(name="CUSTOMER_ID")
public long getId(){..}
....
}
Come possiamo notare l'annotation @TableGenerator
consente di specificare il nome della tabella generatrice,
i nomi delle colonne e la particolare sequence che intendiamo usare (attributo pkColumnValue
) a livello di Entity sul campo annotato con @Id
.