++7.1
…….
7.1.4 The EJB 3 Java Persistence API
La EJB 3 Java Persistence API (JPA) è una tecnologia meta-data-driven POJO, memorizza gli oggetti java in un database (o altro ma di solito è un db relazionale). Non è necessario che estenda una classe o implementi un interfaccia al contrario di ejb 2.0 ma basta che sia un POJO e che usi le annotazioni o l'XML per dare persistenza fornendo le seguenti informazioni:
- cosa i nostri oggetti di dominio sono @Entity and @Embedded annotations
- come sono univocamente identificati annotazione @Id
- quali sono le relazioni tra gli oggetti con le annotazioni @OneToOne,@OneToMany, and @ManyToMany.
- come il dominio dell'oggetto è mappato su una tabella di database @Table, @Column, or @JoinColumn.
7.1.5 Domain objects as Java classes
Un POJO è una entità che è candidata a diventare persistente ed essere memorizzata nel db. In un oggetto di questo tipo ci sono le variabili di tipo private a cui si ha accesso tramite set e get , un Long id che serve per l'identificazione univoca dell'oggetto, degli oggetti Set che serviranno per formare le relazioni con oggetti di altre tabelle.
++7.2 Implementing domain objects with JPA
+++7.2.1 The @Entity annotation
L'annotazione @Entity converte un POJO in una entità.
@Entity public class Category { ... public Category() { ... } public Category(String name) { ... } ... }
Il costruttore deve essere pubblico o protetto per poter instanziare una entità. Si possono ereditare altre classi anche se non sono entità.
Se lo sono come nell'esempio sottostante queste vengono salvate nello strato di persistenza
@Entity public class User { ... String userId; String username; String email; ... } @Entity public class Seller extends User { ... @Entity public class Bidder extends User { ...
7.2.2 Persisting entity data
A un campo di una entità si può accedere in maniera diretta field-based access rendendo public o protected i campi, oppure con un property-based access usando i metodi set e get. Con la seconda possibilità si può avere un controllo più fino dei dati oltre ad altri dettagli spiegati nel paragrafo. Se si usa la seconda le annotazioni vanno messe sopra il getter.
@Id @GeneratedValue(strategy = IDENTITY) @Column(name = "UserId", unique = true, nullable = false) @XmlAttribute public Long getUserId() { return this.userId; } public void setUserId(Long userId) { this.userId = userId; }
Defining a transient field
L'annotazione @Transient serve per non far memorizzare quel dato nel db.
@Transient protected Long activeUserCount;
L'annotazione si può definire anche sul metodo get se si sta usando l'approccio basato sulle proprietà.
Persistent data types
Non ci sono molte limitazioni sul tipo di dati che possono essere mappati sul db. Ecco una tabella di quelli permessi.
Types | Examples |
---|---|
Java primitives | int, double, long |
Java primitives wrappers | java.lang.Integer, java.lang.Double |
String type | java.lang.String |
Java API Serializable types | java.math.BigInteger, java.sql.Date |
User-defined Serializable types | Class that implements java.io.Serializable |
Array types | byte[], char[] |
Enumerated type | {SELLER, BIDDER, CSR, ADMIN} |
Collection of entity types | Set<Category> |
Embeddable class | Classes that are defined @Embeddable |
Della notazione Embeddable se ne discuterà dopo per adesso pensiamo che sia un tipo di classe che incapsula altri dati.
7.2.3 Specifying entity identity
Negli entity bean si utilizza per distinguere in maniera univoca l'id. Ve ne sono tre
- Using the @Id annotation
- Using the @IdClass annotation
- Using the @EmbeddedId annotation
The @Id annotation
La maniera più semplice
@Entity public class Category { ... protected Long id; ... @Id public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } ... }
C'è qualche piccola limitazione sul tipo di dato. Sono ammesse primitives, primitive wrappers, e tipi Serializable come java.lang.String, java.util.Date, and java.sql.Date. Sono vietati i tipi numerici float, Float, double e il Timestamp. Si possono avere chiavi primarie composte usando gli altri due tipi di annotazioni.
The @IdClass annotation
Il problema con le chiavi composte è come effettuare il confronto.
saltato per ora non mi serve
The @EmbeddedId annotation
saltato per ora non mi serve
7.2.4 The @Embeddable annotation
Questa notazione si usa quando un oggetto non ha bisogno di una identificazione univoca perchè si trova dentro un altro oggetto. Qui sotto l'esempio dell'indirizzo. Si sarebbero potuti mettere i campi dell'indirizzo direttamente dentro User ma sarebbe stato meno elegante.
@Embeddable public class Address { protected String streetLine1; protected String streetLine2; protected String city; protected String state; protected String zipCode; protected String country; ... } @Entity public class User { @Id protected Long id; protected String username; protected String firstName; protected String lastName; @Embedded protected Address address; protected String email; protected String phone; ... }
7.3 Entity relationships
Ecco i tipi di annotazioni
Type of relationship | Annotation |
---|---|
One-to-one | @OneToOne |
One-to-many | @OneToMany |
Many-to-one | @ManyToOne |
Many-to-many | @ManyToMany |
7.3.1 @OneToOne
Usata sia in maniera unidirezionale che bidirezionale in base ai riferimenti che ogni entità ha dell'altro lato.
Unidirectional one-to-one
Ecco un esempio
@Entity public class User { @Id protected String userId; protected String email; @OneToOne protected BillingInfo billingInfo; } @Entity public class BillingInfo { @Id protected Long billingId; protected String creditCardType; protected String creditCardNumber; protected String nameOnCreditCard; protected Date creditCardExpiration; protected String bankAccountNumber; protected String bankName; protected String routingNumber; }
tralasciata la parte dopo il codice
Bidirectional one-to-one
Può essere necessaria una relazione bidirezioanale
@Entity public class User { @Id protected String userId; protected String email; @OneToOne protected BillingInfo billingInfo; } @Entity public class BillingInfo { @Id protected Long billingId; protected String creditCardType; protected String routingNumber; @OneToOne(mappedBy="billingInfo", optional="false"); protected User user; }
Vediamo i parametri
mappedBy="billingInfo" dice che c'è “owning” side of the relationship. Quindi se non ho capito male c'è un proprietario della relazione serve per il database mapping.
optional="false" indica che non ci possono essere BillingInfo senza un utente.
@Entity public class Item { @Id protected Long itemId; protected String title; protected String description; protected Date postdate; @OneToMany(mappedBy="item") protected Set<Bid> bids; ... } @Entity public class Bid { @Id protected Long bidId; protected Double amount; protected Date timestamp; ... @ManyToOne protected Item item; ... }
Come abbiamo visto nella uno a uno anche qui con l'attributo mappedBy si identifica l'owner della relazione.
One-to-many relationship
saltato per ora
Many-to-one as owning-side of relationship
saltato per ora
7.3.3 @ManyToMany
Questa relazione può essere uni o bidirezionale ma per sua stessa natura si preferisce la seconda opzione.
@Entity public class Category { @Id protected Long categoryId; protected String name; @ManyToMany protected Set<Item> items; ... } @Entity public class Item { @Id protected Long itemId; protected String title; ... @ManyToMany(mappedBy="items") protected Set<Category> categories; ... }
Assomiglia molto alla uno a molti, c'è la relazione proprietaria e si può usare targetEntity se non si vogliono usare i generics (chi sa che vuol dire?)