Ejb3 In Action Cap7

++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

  1. Using the @Id annotation
  2. Using the @IdClass annotation
  3. 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?)
Salvo diversa indicazione, il contenuto di questa pagina è sotto licenza Creative Commons Attribution-ShareAlike 3.0 License