Persistenza

Il problema degli oggetti persistenti: l'evoluzione della specie

  • JDBC + SQL a mano
  • DAO con JDBC nascosto
  • Nascita dei framework ORM
  • Dualismo EJB vs resto del mondo

Prima di EJB 3.0, la storia parallela: gli Entity beans sono nati come modello con un altissimo livello di astrazione. Le potenzialità teoriche spacciate come la killer-tech. È un esempio del "Troppo presto è troppo tardi"?

Specifica 1.x

  • Tutto punta su BMP
  • Lo scenario non presenta molte alternative credibili
  • Compromesso fra semplicità di gestione e possibilità di personalizzazione del codice
  • Richiedono ancora molto codice
  • Visti ancora con sospetto
  • Manca un supporto XML di alto livello

EJB 2.0

  • CMP diventano una realtà credibile
  • Ancora grosse limitazioni di flessibilità e scarsa adattabilità ai casi sporchi

Purtroppo le limitazioni e le credenze ne hanno decretato l'insuccesso

  • Performance non ottimizzabili
  • Difficoltà nell'adattarsi a scenari formalmente e teoricamente non perfetti
  • Scarsa flessibilità nel risolvere problematiche di produzione (es. fk non nulle)

Nel frattempo: the show "is" going on...

Nascono alternative POJO oriented che rispondono alle esigenze del mercato:

  • Meno potenzialità astrospaziali
  • Alto disaccoppiamento codice-RDBMS
  • Maggior flessibilità
  • Possibilità di lavorare ad alto livello o di scendere nel singolo dettaglio

Hibernate diviene "il" framework ORM

EJB 3.0 in fatto di ORM pare aver imparato la lezione

  • Maggior astrazione
  • Si lavora con POJO che poi diventano data model entities
  • Approccio POJO simil Hibernate ma più semplice
  • XML sparisce ma si può reintrodurre
  • Possibilità di mappare a data model complessi o anche semplicemente realistici
  • Introduce OOP in ORM: non ci sono interfacce o callback schema a cui vincolarsi

È pensato per essere implementato a strati

Sotto il cofano si possono mettere persistence engine differenti.

Se non lo puoi battere... alleati

L'implementazione JBoss utilizza come motore di persistenza Hibernate, Oracle spinge per Toplink.

Seguendo la filosofia di EJB 3.0 anche nell'ambito degli entity, i progettisti hanno per prima cosa semplificato:

  • Staccato il componente dal container
  • Nessuna interfaccia da implementare
  • Nessun metodo di callback
  • Nessun Abstract Persistent Schema
  • Semplici POJO che mappano concettualmente un dataset (tabella di un db)

Eliminazione dello XML

Una cura dimagrante considerevole:

  • Non è più indispensabile avere un IDE potente (ma sempre consigliabile)
  • Si possono creare oggetti anche con altri strumenti e poi renderli entità persistenti "alla EJB"

Una volta deployati i POJO diventano beans soggetti a

  • Sicurezza
  • Transazionalità
  • Lifecycle gestito dal container

Un Entity 3.0 è di fatto un CMP anche se nessuno lo vede.

Si parte dalla definizione di un POJO che rappresenti un'entità

Il POJO diviene un oggetto persistente grazie alla annotazione @Entity.

L'associazione di default usa corrispondenza fra nomi:

  • Nome-bean = nome-tabella
  • Nome campo = nome colonna

Opzionalmente si può specificare la tabella di appoggio e personalizzare la corrispondenza con la colonna usando @Table e @Column.

Un esempio

Definizione della classe, associazione della tabella e attributi

@Entity
@Table(name = "xuser")
public class User {
  private String id;
  private String userName;
  private String email;
  private String firstName;
  private String lastName;
  private String password;

  public User() {
  }

  @Column(name = "id", nullable = false)
  public String getId() {
    return this.id;
  }

  public void setId(String id) {
    this.id = id;
  }

  @Column(name = "user_name", nullable = false)
  public String getUserName() {
    return this.userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }
}

Il mondo reale non è fatto di oggetti isolati

Ogni entità normalmente instaura relazioni con altre entità nel domain model.

Esempio: un utente del sistema (User) è legato con n ruoli (Role).

Le relazioni hanno

  • Molteplicità
  • Navigabilità

Nel mondo OOP le relazioni sono implementate per mezzo di campi di relazione:

@Entity
@Table(name = "xuser")
public class User {
  // ...
  protected Role role;

  @ManyToOne
  // opzionalmente si può definire la colonna di relazione
  // @JoinColumn (name="roleId")
  public Address getRole() {
    return addr;
  }
}

Ereditarietà fra entities

Oltre alla relazione, tutto parte in OOP si ha la relazione Generalizzazione/Specializzazione.

  • Non era possibile in EJB 2.0
  • Tallone d'achille di molti ORM
  • Il modello relazionale non prevede questo costrutto

Due possibili approcci

1. Una tabella per ogni classe della gerarchia 2. Una tabella associata alla classe in fondo alla gerarchia (che come impone la OOP conterrà tutti i campi dei padri più quelli dei figli)

Una tabella per classe

  • Duplicazione di informazioni
  • Debole al refactoring (una modifica alla classe base deve essere propagata a tutte le tabelle)
  • Debole alla modifica puntuale

Una tabella associata alla classe in fondo alla gerarchia

  • La tabella contiene tutte le colonne della classe figlia
  • Gli oggetti padre che non hanno determinate proprietà impostano a null i valori
  • Differenziare le tipologie di oggetto con il solo controllo a null è un design debole e propenso a errori
  • È previsto un meccanismo basato su una colonna di differenziazione
  • EJB 3.0 supporta entrambe le strategie di ereditarietà (default la seconda)

L'esempio mostra un'entità (PowerUser) estensione dell'entità base (User).

La colonna discriminante è associata al campo person_type

Se person_type=="PW" allora si tratta di un'istanza del tipo figlio. Altrimenti è un utente normale.

@Entity
@Inheritance(discriminatorValue="PW")
@DiscriminatorColumn(name="person_type")
public class PowerUser extends User {
  protected int level;

  public void setLevel(int l) {
    this.level = l;
  }

  public int getLevel() {
    return level;
  }
}

Conclusioni

In questa terza parte abbiamo esplorato il mondo della persistenza in EJB 3.0, vedendo come la specifica abbia finalmente colmato il gap con i framework ORM più moderni. L'approccio POJO-based, l'uso delle annotazioni al posto degli XML descriptor, e il supporto per concetti avanzati come l'ereditarietà tra entities rendono EJB 3.0 una soluzione completa e moderna per la gestione della persistenza nelle applicazioni enterprise.

Nelle prossime parti della serie vedremo altri aspetti importanti di EJB 3.0, inclusi i Message Driven Beans, i Web Service beans e il servizio di timer.