Visualizzazione post con etichetta Hibernate. Mostra tutti i post
Visualizzazione post con etichetta Hibernate. Mostra tutti i post

lunedì 18 agosto 2014

Hibernate e SQLite

Vai all'indice

Negli esempi precedenti per comodità ho utilizzato Apache Derby, tuttavia Hibernate funziona altrettanto bene con qualsiasi DB semplicemente modificando i parametri di configurazione e la dependency del file POM di Maven. Un caso interessante da trattare è sicuramente l'integrazione di Hibernate con Sqlite.



Molto spesso durante lo sviluppo di un progetto può nascere la necessità di gestire piccole quantità di dati, tali da non giustificare l’uso di un database. La soluzione sicuramente più immediata consiste nell’utilizzo di file di testo o XML come base di dati. Una soluzione alternativa, e a mio avviso più efficace, è nell’uso di SQLite.
SQLite è una piccola libreria  che implementa un vero e proprio motore di database le cui caratteristiche  sono:

  • la semplicità: nessun bisogno di installazione e configurazione;
  • la compattezza: un intero database è contenuto in un unico file, in questo modo è possibile inserire il file direttamente all'interno dell'applicazione stessa!
  • il supporto degli standard: SQLite implementa quasi completamente il linguaggio SQL;
  • la velocità;
  • il costo: GRATUITO.


Per la creazione del database ho scaricato SQLiteStudio, un semplice tool scaricabile dal sito http://sqlitestudio.pl e che non richiede installazione (esiste anche un plugin di Firefox che fa lo stesso lavoro).
Ho creato un nuovo database l'ho chiamato mydb, quindi ho definito la solita tabella "utente" secondo la struttura descritta dall'immagine sottostante.




A questo punto ho ottenuto un file mydb.db, che troviamo nella cartella dove ho posizionato SQLiteStudio e che contiene il DB appena definito.

Metto da parte il file contenente il db appena creato, apro Eclipse e creo un nuovo progetto Maven seguendo questo post.
Finora nel file POM ho inserito la dependency per il caricamento del driver Apache Derby, ora per il caricamento della libreria JDBC di SQLite definisco la dependency:


        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.7.2</version>
        </dependency>


Creo il file Utente.java all'interno della cartella jar e all'interno definisco l'entità Utente.


package jar;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "utente")
public class Utente {

@Id
private Integer userid;
private String nome;
private String cognome;

public Utente() {

}

public Utente(Integer userid, String nome, String cognome) {
this.userid = userid;
this.nome = nome;
this.cognome = cognome;
}

// Definisco getter e setter

}


Nella cartella resources definisco il file 'hibernate.cfg.xml'.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="dialect">org.hibernate.dialect.SQLiteDialect</property>
<property name="connection.driver_class">org.sqlite.JDBC</property>
<property name="connection.url">jdbc:sqlite:mydb.db</property>
<property name="connection.username"></property>
<property name="connection.password"></property>

<property name="hibernate.hbm2ddl.auto">update</property>

<mapping class="jar.Utente"/>
</session-factory>
</hibernate-configuration>


Ho creato il pacchetto 'org.hibernate.dialect' nel progetto ed ho inserito il file SQLiteDialect, il file dialect è utilizzato da Hibernate per creare query SQL per lo specifico database, il file è scaricabile da diverse fonti nel web.

      /*
 * The author disclaims copyright to this source code.  In place of
 * a legal notice, here is a blessing:
 *
 *    May you do good and not evil.
 *    May you find forgiveness for yourself and forgive others.
 *    May you share freely, never taking more than you give.
 *
 */
package org.hibernate.dialect;

import java.sql.Types;

import org.hibernate.dialect.function.AbstractAnsiTrimEmulationFunction;
import org.hibernate.dialect.function.NoArgSQLFunction;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.type.StandardBasicTypes;

public class SQLiteDialect extends Dialect {
  public SQLiteDialect() {
    registerColumnType(Types.BIT, "boolean");
    registerColumnType(Types.TINYINT, "tinyint");
    registerColumnType(Types.SMALLINT, "smallint");
    registerColumnType(Types.INTEGER, "integer");
    registerColumnType(Types.BIGINT, "bigint");
    registerColumnType(Types.FLOAT, "float");
    registerColumnType(Types.REAL, "real");
    registerColumnType(Types.DOUBLE, "double");
    registerColumnType(Types.NUMERIC, "numeric($p, $s)");
    registerColumnType(Types.DECIMAL, "decimal");
    registerColumnType(Types.CHAR, "char");
    registerColumnType(Types.VARCHAR, "varchar($l)");
    registerColumnType(Types.LONGVARCHAR, "longvarchar");
    registerColumnType(Types.DATE, "date");
    registerColumnType(Types.TIME, "time");
    registerColumnType(Types.TIMESTAMP, "datetime");
    registerColumnType(Types.BINARY, "blob");
    registerColumnType(Types.VARBINARY, "blob");
    registerColumnType(Types.LONGVARBINARY, "blob");
    registerColumnType(Types.BLOB, "blob");
    registerColumnType(Types.CLOB, "clob");
    registerColumnType(Types.BOOLEAN, "boolean");

    //registerFunction( "abs", new StandardSQLFunction("abs") );
    registerFunction( "concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", "") );
    //registerFunction( "length", new StandardSQLFunction("length", StandardBasicTypes.LONG) );
    //registerFunction( "lower", new StandardSQLFunction("lower") );
    registerFunction( "mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2" ) );
    registerFunction( "quote", new StandardSQLFunction("quote", StandardBasicTypes.STRING) );
    registerFunction( "random", new NoArgSQLFunction("random", StandardBasicTypes.INTEGER) );
    registerFunction( "round", new StandardSQLFunction("round") );
    registerFunction( "substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING) );
    registerFunction( "substring", new SQLFunctionTemplate( StandardBasicTypes.STRING, "substr(?1, ?2, ?3)" ) );
    registerFunction( "trim", new AbstractAnsiTrimEmulationFunction() {
        protected SQLFunction resolveBothSpaceTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1)");
        }

        protected SQLFunction resolveBothSpaceTrimFromFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?2)");
        }

        protected SQLFunction resolveLeadingSpaceTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1)");
        }

        protected SQLFunction resolveTrailingSpaceTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1)");
        }

        protected SQLFunction resolveBothTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1, ?2)");
        }

        protected SQLFunction resolveLeadingTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1, ?2)");
        }

        protected SQLFunction resolveTrailingTrimFunction() {
          return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1, ?2)");
        }
    } );
    //registerFunction( "upper", new StandardSQLFunction("upper") );
  }

  public boolean supportsIdentityColumns() {
    return true;
  }

  /*
  public boolean supportsInsertSelectIdentity() {
    return true; // As specify in NHibernate dialect
  }
  */

  public boolean hasDataTypeInIdentityColumn() {
    return false; // As specify in NHibernate dialect
  }

  /*
  public String appendIdentitySelectToInsert(String insertString) {
    return new StringBuffer(insertString.length()+30). // As specify in NHibernate dialect
      append(insertString).
      append("; ").append(getIdentitySelectString()).
      toString();
  }
  */

  public String getIdentityColumnString() {
    // return "integer primary key autoincrement";
    return "integer";
  }

  public String getIdentitySelectString() {
    return "select last_insert_rowid()";
  }

  public boolean supportsLimit() {
    return true;
  }

  public boolean bindLimitParametersInReverseOrder() {
    return true;
  }

  protected String getLimitString(String query, boolean hasOffset) {
    return new StringBuffer(query.length()+20).
      append(query).
      append(hasOffset ? " limit ? offset ?" : " limit ?").
      toString();
  }

  public boolean supportsTemporaryTables() {
    return true;
  }

  public String getCreateTemporaryTableString() {
    return "create temporary table if not exists";
  }

  public boolean dropTemporaryTableAfterUse() {
    return true; // TODO Validate
  }

  public boolean supportsCurrentTimestampSelection() {
    return true;
  }

  public boolean isCurrentTimestampSelectStringCallable() {
    return false;
  }

  public String getCurrentTimestampSelectString() {
    return "select current_timestamp";
  }

  public boolean supportsUnionAll() {
    return true;
  }

  public boolean hasAlterTable() {
    return false; // As specify in NHibernate dialect
  }

  public boolean dropConstraints() {
    return false;
  }

  /*
  public String getAddColumnString() {
    return "add column";
  }
  */

  public String getForUpdateString() {
    return "";
  }

  public boolean supportsOuterJoinForUpdate() {
    return false;
  }

  public String getDropForeignKeyString() {
    throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
  }

  public String getAddForeignKeyConstraintString(String constraintName,
      String[] foreignKey, String referencedTable, String[] primaryKey,
      boolean referencesPrimaryKey) {
    throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
  }

  public String getAddPrimaryKeyConstraintString(String constraintName) {
    throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
  }

  public boolean supportsIfExistsBeforeTableName() {
    return true;
  }

  public boolean supportsCascadeDelete() {
    return true;
  }

  /* not case insensitive for unicode characters by default (ICU extension needed)
  public boolean supportsCaseInsensitiveLike() {
    return true;
  }
  */

  public boolean supportsTupleDistinctCounts() {
    return false;
  }

  public String getSelectGUIDString() {
    return "select hex(randomblob(16))";
  }
}


Ora creo la classe HibernateUtil che mi aiuta a creare la SessionFactory dal file di configurazione di Hibernate. Il SessionFactory viene utilizzato per ottenere le istanze delle sessioni che rappresentano i singoli processi.

package jar;

import java.util.Properties; import org.hibernate.SessionFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.hibernate.HibernateException;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistryBuilder;

public class HibernateUtil {

  
  private static SessionFactory sessionFactory = null;  
  private static ServiceRegistry serviceRegistry = null;

    public static SessionFactory getSessionFactory() {

      try {  
        Configuration configuration = new Configuration();  
        configuration.configure();  
        
        Properties properties = configuration.getProperties();
      
        serviceRegistry = new ServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();          
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);  
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
      
      return sessionFactory; 
    }
}


A questo punto riprendo il file mydb.db creato in precedenza e lo inserisco direttamente all'interno dell'applicazione con un semplice copia-incolla sull'icona di progetto.

La classe Main.java esegue le operazioni di CRUD. Come visto in precedenza tramite questa classe è possibile eseguire il progetto.


package jar;

import java.sql.Date;
import java.util.List;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public class Main {

   @SuppressWarnings("unchecked")
   public static void main(String[] args) {
      SessionFactory sessionFactory = HibernateUtil.configureSessionFactory();
      Session session = null;
      Transaction tx=null;
      
      try {

         session = sessionFactory.openSession();
         tx = session.beginTransaction();

       // Ripulisco il database
         List<Utente> UtenteList = session.createQuery("from Utente").list();
         for (Utente Utex : UtenteList) {
            session.delete(Utex);
         }         
         
       // Verifico sia vuoto
         for (Utente Utente : UtenteList) {
            System.out.println("Utente Id: " + Utente.getUserid() + " | Name:"  + Utente.getNome() + " | Email:" + Utente.getCognome());
         }            

         // Creo le entità Utente che salverò nel database sqlite
         Utente myUtente = new Utente(11, "Pippo", "Pippo");
         Utente yourUtente = new Utente(12, "Pluto", "Pluto");
         Utente herUtente = new Utente(13, "Paperino", "Paperino");
         
         // Salvo nel database
         session.save(myUtente);
         session.save(yourUtente);
         session.save(herUtente);   
         
         UtenteList = session.createQuery("from Utente").list();         
         // Fetching sui dati salvati
         for (Utente Utente : UtenteList) {
            System.out.println("Utente Id: " + Utente.getUserid() + " | Name:"  + Utente.getNome() + " | Email:" + Utente.getCognome());
         }         
         
         // Aggiornamento
         myUtente.setNome("Gino");
         
         session.merge(myUtente);
         
         // Cancellazione    
         session.delete(herUtente);
         
         // Eseguo un'altra estrazione 
         UtenteList = session.createQuery("from Utente").list();
         
         for (Utente Utente : UtenteList) {
            System.out.println("$$$ Id: " + Utente.getUserid() + " | Name:"  + Utente.getNome() + " | Email:" + Utente.getCognome());
         }
         
         // Commit.
         session.flush();
         tx.commit();
   } catch (Exception ex) {
      ex.printStackTrace();
      
      // Rollback.
      tx.rollback();
   } finally{
      if(session != null) {
         session.close();
      }
   }         

   }
}


Di seguito riporto l'alberatura del progetto.





Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!

lunedì 11 agosto 2014

Query Hibernate con Criteria

Con Hibernate l'interazione tra applicazione e database avviene tramite HQL e JPQL, linguaggi ad hoc per astrarre la logica relazionale e lavorare direttamente ad oggetti. Tuttavia esiste un metodo alternativo di manipolare e interrogare i dati delle tabelle. Criteria API consente di creare un oggetto con dei criteri di programmazione in cui è possibile applicare delle regole di filtraggio e condizioni logiche.

L'interfaccia Session fornisce il metodo createCriteria(), il quale crea un oggetto Criteria che restituisce istanze della classe dell'oggetto in persistenza.
Di seguito un semplice esempio di una query criteria che restituisce un oggetto corrispondente alla classe Utente.

Criteria cr = session.createCriteria(Utente.class);
List results = cr.list();

E' possibile usare il metodo add() per aggiungere restrizioni alle query con criteria. Supponendo di disporre di una tabella "utente" contenente un campo "eta", l'esempio di seguito aggiunge una restrizione che restituisce gli utenti con un'età superiore ai 30 anni.

Criteria cr = session.createCriteria(Utente.class);
cr.add(Restrictions.eq("eta", 30));
List results = cr.list();

Di seguito altri esempi di Restrictions.

Criteria cr = session.createCriteria(Utente.class);

// Restituisce utenti con età superiore ai 30 anni.
cr.add(Restrictions.gt("eta", 30));

// Restituisce utenti con età inferiore ai 30 anni.
cr.add(Restrictions.lt("eta", 30));

// Restituisce utenti col nome che inizia con Gian
cr.add(Restrictions.like("nome", "Gian%"));

// Restituisce utenti con età compresa tra i 20 e i 30 anni.
cr.add(Restrictions.between("eta", 20, 30));

// Verifica se il campo è nullo
cr.add(Restrictions.isNull("eta"));

// Verifica che il campo non sia vuoto
cr.add(Restrictions.isNotEmpty("eta"));


Con Criteria è possibile anche ordinare e aggregare i risultati.

Criteria cr = session.createCriteria(Utente.class);

// Ordina gli utenti per età discendente
cr.addOrder(Order.desc("eta"));

// Conta le righe totali.
cr.setProjection(Projections.rowCount());

// Restituisce l'età più alta.
cr.setProjection(Projections.max("eta"));

// Restituisce l'età media.
cr.setProjection(Projections.avg("eta"));



Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!

lunedì 4 agosto 2014

L'auto-referenziazione in Hibernate

Vai all'indice

Un breve accenno merita la gestione dell'autoreferenziazione in Hibernate in particolare relazioni: uno-a-molti e molti-a-molti.
Una tabella è autoreferenziata quando è correlata a se stessa da due campi diversi. Utilizzando  un esempio specifico, sempre la tabella Utente (pensiamo agli utenti come impiegati di un ufficio) può includere l'ID di un manager responsabile di altri utenti nella stessa tabella. Questa relazione è definita self-join o self-reference che è una sorta di struttura padre/figlio.


L'auto-referenziazione in Hibernate

Nella tabella Utente, è necessario definire una colonna MANAGER_ID mappata nella tabella stessa. Così per ogni dipendente verrà memorizzato id del proprio responsabile.

   ...
    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="manager_id")
    private Utente manager;

    @OneToMany(mappedBy="manager")
    private Set<Utente> subord = new HashSet<Utente>();
   ...

Nell'entità Utente sono state definiti due nuovi attributi: manager e subord che è un Set <Utente>. manager viene mappato con l'annotazione @ManyToOne mentre subord con @OneToMany. All'interno di @OneToMany è stato definito mappedBy = "manager" questo rende l'oggetto manager parte proprietaria dell'associazione.

Questa appena descrittà è un'associazione uno-a-molti, ma è possibile definire anche relazioni molti-a-molti autoreferenziate. Basti pensare ad una associazione del tipo utente e colleghi (anch'essi definiti come utenti). In questo caso però è necessario definire una tabella di collegamento come segue.


CREATE TABLE utente_collega (userid int NOT NULL, collid int NOT NULL,  PRIMARY KEY (userid, collid), CONSTRAINT FK_UFF FOREIGN KEY (userid) REFERENCES utente (userid),  CONSTRAINT FK_APP FOREIGN KEY (collid) REFERENCES applicazione (collid);


Nell'entità Utente vanno definite le seguenti annotazioni:

   ...
   @ManyToMany(cascade={CascadeType.ALL})
    @JoinTable(name="utentee_collega",
        joinColumns={@JoinColumn(name="userid")},
        inverseJoinColumns={@JoinColumn(name="collid")})
    private Set<Utente> collx = new HashSet<Utente>();

    @ManyToMany(mappedBy="collx")
    private Set<Utente> utex = new HashSet<Utente>();
   ...

Le annotazioni sono le stesse usate per definire una relazione molti a molti. In questo caso è necessario definire nell'entità Utente sia le annotazione della parte proprietaria che non proprietaria.



Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!

martedì 29 luglio 2014

Hibernate relazione molti-a-molti

Vai all'indice

Una relazione molti-a-molti esiste quando un singolo record in una tabella può essere correlato a molti record in una seconda, e un singolo record nella seconda a molti record nella prima tabella.
Per questo esempio utilizzerò le tabelle utente e applicazione definite nel primo post, da notare che esiste una terza tabella utente_applicazione che mette in collegamento le altre due. Ogni utente può essere collegato a più applicazioni ed ogni applicazione può essere utilizzata da più utenti.



Di seguito modifico l'entità Utente.java dell'esempio precedente per la gestione della relazione molti-a-molti e definisco la nuova entità Applicazione.java.

package jar;

import java.sql.Date;
import java.util.HashSet; 
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.ManyToOne;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumns;
import javax.persistence.JoinColumn;
import javax.persistence.Table;

@Entity
@Table(name="utente")
public class Utente {

   @Id
   @GeneratedValue
   @Column(name="userid")
   private int userId;
   
   @Column(name="nome")
   private String nome;
   
   @Column(name="cognome")
   private String cognome;
   
   @Column(name="ruolo")
   private String ruolo;
   
   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "utente")
    @JoinColumn(name="userid")
   private Dettaglioutente dettaglioutente;
    
    @ManyToOne
    @JoinColumn(name="ufficioId", 
                insertable=false, updatable=false, 
                nullable=false)
    private Ufficio ufficio;
    
    @ManyToMany(fetch = FetchType.LAZY,cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name="utente_applicazione", 
                joinColumns={@JoinColumn(name="userid")}, 
                inverseJoinColumns={@JoinColumn(name="appid")})
    private Set<Applicazione> applicazioni = new HashSet<Applicazione>();  

   
   public Utente() {
      
   }
   
   public Utente(String nome, String cognome, String ruolo) {
      this.nome = nome;
      this.cognome = cognome;
      this.ruolo = ruolo;
      
   }
   
   // Metodi Getter e Setter
   

   public Set<Applicazione> getApplicazioni() {
      return applicazioni;
   }

   public void setApplicazioni(Set<Applicazione> applicazioni) {
      this.applicazioni = applicazioni;
   }   

   public int getUserId() {
      return userId;
   }

   public void setUserId(int userId) {
      this.userId = userId;
   }


   public String getNome() {
      return nome;
   }

   public void setNome(String nome) {
      this.nome = nome;
   }

   public String getCognome() {
      return cognome;
   }

   public void setCognome(String cognome) {
      this.cognome = cognome;
   }

   public String getRuolo() {
      return ruolo;
   }

   public void setRuolo(String ruolo) {
      this.ruolo = ruolo;
   }

   public Dettaglioutente getDettaglioutente() {
      return dettaglioutente;
   }

   public void setDettaglioutente(Dettaglioutente dettaglioutente) {
      this.dettaglioutente = dettaglioutente;
   }
   
   public Ufficio getUfficio() {
      return ufficio;
   }

   public void setUfficio(Ufficio ufficio) {
      this.ufficio = ufficio;
   }   
}


package jar;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="applicazione")
public class Applicazione {

    @Id
    @Column(name="appid")
    @GeneratedValue
    private int appid;

    @Column(name="nomeapp")
    private String nomeapp;

    @Column(name="desrizioneapp")
    private String descrizioneapp;    
     
    @ManyToMany(fetch = FetchType.LAZY, mappedBy="applicazioni", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<Utente> utenti = new HashSet<Utente>();
    
   public Applicazione() {
      
   }

    public Applicazione(String nomeapp, String descrizioneapp) {
        this.nomeapp = nomeapp;
        this.descrizioneapp = descrizioneapp;
    }

   public int getAppid() {
      return appid;
   }

   public void setAppid(int appid) {
      this.appid = appid;
   }

   public String getNomeapp() {
      return nomeapp;
   }

   public void setNomeapp(String nomeapp) {
      this.nomeapp = nomeapp;
   }

   public String getDescrizioneapp() {
      return descrizioneapp;
   }

   public void setDescrizioneapp(String descrizioneapp) {
      this.descrizioneapp = descrizioneapp;
   }

   public Set<Utente> getUtenti() {
      return utenti;
   }

   public void setUtenti(Set<Utente> utenti) {
      this.utenti = utenti;
   }
   

}

L'annotazione @ManyToMany viene utilizzata per definire una relazione molti-a-molti tra le entità Utente e Applicazione. Ogni associazione molti-a-molti ha una parte proprietaria e una non proprietaria.
L’annotazione @JoinTable  si definisce sul lato proprietario di una relazione molti-a-molti e serve per indicare la tabella che registra le associazioni, che nel nostro caso è Utente_applicazione. Se l'associazione è bidirezionale, entrambe le parti possono essere definite proprietarie.
L’attributo name dell’annotazione @JoinTable specifica la tabella che memorizza i riferimenti alle primary key delle tabelle utente e applicazione.
Questa tabella contiene le colonne userid e appid che sono le chiavi esterne che fanno riferimento alle chiavi primarie delle due tabelle.
Gli elementi joinColumns e inverseJoinColumns fanno riferimento alle primary key; il primo descrive la parte proprietaria della relazione. L’annotazione @JoinColumn  viene utilizzata per definire la colonna di collegamento in entrambe le tabelle.
L’attributo mappedBy serve per indicare l’entità proprietaria della relazione nell’entità subordinata e viene usato esclusivamente nel caso di una relazione bidirezionale.
Il parametro cascade  comunica all’EntityManager come estendere un’operazione di persistenza su una particolare entità verso le entità a questa collegate.
Di default l’elemento cascade è vuoto e quindi le operazioni di persistenza non vengono diffuse.
I valori possono essere settati a ALL, MERGE, PERSIST, REFRESH, REMOVE.
Da notare che ho usato <SET> per mappare la tabella Applicazione su Utente e viceversa. <set> può memorizzare solo oggetti unici, ciò significa che elementi duplicati non possono essere contenuti in un set. Quando si aggiunge lo stesso elemento di un set per la seconda volta, andrà a sostituire quello già esistente. Il tipo corrispondente di un <set> in Java è java.util.Set.

Quindi modifico il file: /src/main/resources/hibernate.cfg.xml mappando jar.Applicazione:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
  <!-- DB connection settings -->
  <property name="connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
  <property name="connection.url">jdbc:derby://localhost:1527/derby/derbyDB</property>
  <property name="connection.username">tst</property>
  <property name="connection.password">test</property>

  <property name="connection.pool_size">1</property>
  <property name="dialect">org.hibernate.dialect.DerbyDialect</property>
  <property name="current_session_context_class">thread</property>
  <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
  <property name="show_sql">true</property>
  <property name="hbm2ddl.auto">validate</property>

  <mapping class="jar.Utente"/>
  <mapping class="jar.Dettaglioutente"/>
  <mapping class="jar.Ufficio"/>
  <mapping class="jar.Applicazione"/>

</session-factory>
</hibernate-configuration>

La classe HibernateUtil rimane invariata.
La classe Main.java esegue le operazioni di CRUD (Inserimento, lettura e cancellazione). E' possibile eseguire l'applicazione cliccando col tasto destro su questa classe, quindi selezionare Run as > Java Application. Il risultato dell'elaborazione è visibile nella scheda console di Eclipse.

package jar;

import java.sql.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.HibernateException;

public class Main {

   @SuppressWarnings("unchecked")
   public static void main(String[] args) {

      System.out.println("Hibernate Test");
      
      SessionFactory sf = HibernateUtil.getSessionFactory();

      int iduff = 0;
      
      // Inserimento
      Session session = sf.openSession();
      session.beginTransaction();   
      int delIdapp = 0; //definisco l'id dell'app. che cancellerò
      try {
           Applicazione app1 = new Applicazione("SAP", "Sistema gestionale");
           Applicazione app2 = new Applicazione("GIS", "Sistemi territoriali");
           session.save(app1);
           session.save(app2);
           delIdapp = app1.getAppid();

         Utente ute1 = new Utente("Franco", "Neri", "Utente");
         Utente ute2 = new Utente("Giovanni", "Bianchi", "Admin");   
               
         ute1.getApplicazioni().add(app1);
         ute1.getApplicazioni().add(app2);
         ute2.getApplicazioni().add(app1);
         ute2.getApplicazioni().add(app2);
         session.save(ute1);
         session.save(ute2);

         session.getTransaction().commit();
      }catch (HibernateException e) {
         session.getTransaction().rollback();
           e.printStackTrace();
      } finally {
         session.close();
      }
      
      Lista(); 

      // Cancello una applicazione e tutte le associazioni con gli utenti
      session = sf.openSession();
      session.beginTransaction();         
      try {   
          Applicazione appx = (Applicazione) session.load(Applicazione.class, delIdapp);
          List<Utente> utenti = session.createQuery("from Utente").list();
             for (Utente utex : utenti) {
                utex.getApplicazioni().remove(appx);
                session.save(utex);
             } 
             session.delete(appx);
         
         session.getTransaction().commit();   
      }catch (HibernateException e) {
         session.getTransaction().rollback();
           e.printStackTrace();
      } finally {
          session.close();
      }
       
       Lista();       

   }

   @SuppressWarnings("unchecked")
   public static void Lista() {
      Session session = HibernateUtil.getSessionFactory().openSession();
      session.beginTransaction();   
      System.out.println("Lista utenti ufficio");
      List<Utente> uts = session.createQuery("from Utente").list();
      for (Utente ut1 : uts) {
         System.out.println("Info utente " + ut1.getNome()  + " , "
            + ut1.getCognome() + ", "
            + ut1.getRuolo()); 
            for(Applicazione appy : ut1.getApplicazioni()) {
                    System.out.println("Nome applicazione associate all'utente " + appy.getNomeapp());
                }
              
      }
      session.close();
   }
}

Di seguito riporto tutti i moduli creati finora nel progetto.





Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!