Newsgroup: it.comp.java
Titolo: Hibernate e corretta impostazione delle relazioni

Salve a tutti,
ho iniziato a sperimentare hibernate e facendo delle piccole prove lo
trovo molto interessante. Adesso di tratta di utilizzarlo in programma
vero e proprio e vorrei avere un approccio corretto.
Le mie abitudini mi hanno sempre portato a strutturare una tabella nel
seguente modo:
id ......... campo univoco numerico - progressivo
codcli ... campo numerico (codice cliente)
descli ... campo stringa (descrizione cliente)
ecc. ecc.
Ogni mia tabella inizia con il campo id e questo mi aiuta a
standardizzare il codice per modificare o eliminare una riga. Mentre
le relazioni MOLTI A UNO le utilizzo sul secondo campo.
Secondo voi ci sono delle controindicazioni nel definire due chiavi
come segue:
id ......... chiave univoca
codcli ... chiave primaria (il campo viene annotato come @Id).
Se volessi ottenere un numero progressivo automatico per il campo id
come devo scrivere l'annotazione?
Grazie
Biagio

Biagio ha scritto:

Il termine chiave univoca non esiste.
Sul Database
esiste :
-) Primary Key. E' la chiave primaria, 1 o piu' campi, nel tuo caso se metti
PK codcli poi metti un unique su ID
In hibernate metti l'annotazione @Id sul "getter" della PK nel tuo caso
codcli
-) Foreign Key. E? un vincolo ch eindica la relazione n:1. Nella teoria dei
database la foreign key relazione un campo ( o piu' ) di una tabella con la
chiave primaria di una altra tabella.
QUindi In hibernate le relazioni N:1 le mappi con una property sulla tabella N
che si "collega" alla Primary key della tabella 1.
La relazione la setti come nell'esempio sotto con @ManyToOne e @JoinColumn
Join column dice quale e' la colonna della tabella N che ospitera' la primary
key della tabella 1
-) Unique e' un Unique constraint o vincolo di unicita'
in hibernate lo setti nel @column come vedi sotto nell'esempio
@Entity
@Name("iscrizione")
@Table(name="xgateiscrizione")
@SequenceGenerator(name="sequenz", 
		           sequenceName="s_xgateiscrizione", 
		           initialValue=1000, 
		           allocationSize=1) 
public class Iscrizione  implements Serializable
{
	private Long idIscrizione;
 
	private String nome;
	private String cognome;
	private String ragioneSociale;
	private String via;
	private String numero;
	private String localita;
	private String provincia;
	private String cap;
	private String telefono;
	private String fax;
	private String email;
	private String funzione;
	private String contattoPersona;
	private String contattoTelefono;
 
	private Corso  			corso;
	private Regione 		regione;
	private Provincia 		prov;
	private IscrizioneMail 	iscrizionemail;
 
	@Id 
	@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="sequenz") 
	@Column(name = "id_iscrizione")
	public Long getIdIscrizione() {
		return idIscrizione;
	}
	public void setIdIscrizione(Long idIscrizione) {
		this.idIscrizione = idIscrizione;
	}
 
 
	@ManyToOne( fetch = FetchType.EAGER)
	@JoinColumn(name = "regione", unique = false, nullable = true, insertable =
true, updatable = true)
	public Regione getRegione() {
		return regione;
	}
.....
L'unica piccola confusione che ti si puo' creare e' puramente di nomi perche'
metterai @Id sulla property "codcli" e non su quella "id"
di fatto in un db come il tuo diventa quasi inutile a mio avviso l'id, ma se
ti piace averlo nulla ti vieta di tenerlo
P.S. Io personalmente farei l'inverso cioe' metterei l'ID come PK e l'unique
sul codcli.
Pero' poi la relazione molti a uno si fa con gli id e non con il codcli
ciao
-- 


Grazie, sei stato chiarissimo. Inizio a capire qualcosa in più. Mi
piace Hibernate anche per il fatto di poter cambiare database senza
grosse variazioni al codice.
Uso NetBeans come IDE perchè devo velocizzare i tempi di sviluppo,
anche se magari il codice è un po' ridondante.
Peccato che non ho trovato un plugin per NetBeans per disegnare
visivamente le relazioni.
Accetto suggerimenti di ogni genere. Se ci sono siti o eventuali
tutorial che ritenete fondamentali per apprendere bene l'uso di JPA e
Hibernate, vi ringrazio in anticipo.
Biagio

 Biagio
Beh, se accetti consigli di ogni genere, suggerisco un paio di
cosette:
. Elimina quella colonna id, non ti serve a nulla. Hai già codcli,
univoco nella tua tabella, annota questo, affinché sia la tua chiave
primaria:
        @Id
 
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="sequenz")
        @Column(name = "cod_cliente")
        public Long getCodCliente() {
                return codCliente;
        }
. Dai alle colonne dei nomi un po' più parlanti, ad esempio,
codCliente e descrizione. Una convenzione con la quale mi sono trovato
bene è CamelCase nelle classi java e nome della colonna separato da
(_) undersquare nel DB.
. Se vuoi, ma solo se vuoi, in hibernate e JPA, puoi annotare
direttamente le proprietà private della classe, io lo preferisco,
perché hai subito la definizione dei campi in cima alla classe invece
che sui getter.
. Attenzione alle sequence, perché in alcuni db, mysql ad esempio, non
sono supportate e potresti aver bisogno di un campo di tipo
autoincrement:
	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "cod_cliente", unique = true, nullable = false)
	private Long codCliente;
In bocca al lupo :)
Ciao, Davide.

	private Long codCliente;
Si si, sui Generated ho semplicemente copiato e incollato una classe che avveo
sottomano ieri sera.
Senza entrare in dettaglio sull'argomento suggerisco all OP quanto meno di
leggere il libro su questo aregomento ( sono 2 o 3 paginette ) perche'
hibernate ha tanti modi di generare.
Volendo discutere con te Davide invece io mi trovo meglio con le sequence, il
motivo e' che se hai un cluster o dei nodi balancing non so come se la cavano
3d IDENTITY e in generale la generazione hibernate. Ripassero' appena ho
voglia :-)
La generazione e' un argomento informatico sempre di attualita' :-)
ciauz
-- 

che sui getter.
Vediamo se ho capito .... scusate ma sono alle prime armi.
Uso le annotazioni generate direttamente da NetBeans che dovrebbe
comportarsi esattamente come dici tu, se non sbaglio.
Esempio:
public class Anagrafica implements Serializable {
    private static final long serialVersionUID = 1L;
@Id
    @Basic(optional = false)
    @Column(name = "codanag", nullable = false)
    private Integer codanag;
public Integer getCodanag() {
        return codanag;
    }
    public void setCodanag(Integer codanag) {
        this.codanag = codanag;
    }
A questo ti riferivi ?
Biagio


Ciao Biagio, una domanda, che DB stai utilizzando? Che strategia
adotti per la chiave primaria? Sarà un codice scritto dall'operatore o
un numero generato dal sistema?
Ritengo abbastanza ragionevolmente che userai una chiave primaria
numerica. Hibernate, è vero che scrive le query nel dialetto corretto,
ma si deve comunque appoggiare al DB sottostante, per alcune
funzionalità.
Una di queste è la generazione della chiave primaria, per dirla molto
volgarmente.
Oracle, per risolvere questo problema, usa un oggetto che si chiama
sequence, ovvero un contatore che, ogni volta che lo interroghi, ti
restituisce il vecchio numero più 1.
Se usi questo DB Server, devi dichiarare nella classe che utilizzi una
sequence e nella colonna la referenzi. Esattamente come ti scrive n
n.
MySQL invece non ha le sequence e per risolvere lo stesso problema
devi dichiarare una colonna come autoincrementale, cioè che ad ogni
insert, viene automaticamente assegnato il valore grande di quella
colonna +1. Il risultato è simile alla sequence, anzi, direi
addirittura più comodo, ma questa è solo una questione di gusti.
Se usi quindi MySQL, non devi dichiarare nulla nella classe, ma basta
definire il campo come autoincrement, esattamente come segue:
import static javax.persistence.GenerationType.IDENTITY;
/// definizione della classe e tutto il resto...
	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "USER_ID", unique = true, nullable = false)
	private Long userId;
Ciao, Davide.

 La generazione e' un argomento informatico sempre di attualita' :-)
Ben detto!
Ciao, Davide.

Ciao, Davide.
Ciao Nicola
-- 


Ciao Davide,
ho scelto hibernate con le annotazioni jpa perché volevo ottenere due
risultati:
- scrivere meno codice possibile;
- rendere l'applicativo il più possibile indipendente dal database.
Ora mi rendo conto che ciò che guadagno da una parte perdo dall'altra.
Ho il sospetto che se voglio utilizzare la stessa applicazione su
MySql e Postgres, le annotazioni JPA non possano essere gestite a run-
time, o sbaglio?
Alcune chiavi primare sono numeriche e quindi sarebbe un'ottima cosa
lasciare che sia hibernate ed il database a gestirle. Però vedo che
ogni database usa un sistema proprietario.
Altre chiavi sono alfanumeriche e digitate dall'utente.
Inoltre, proprio perché non voglio farmi mancare nulla, avrò anche
chiavi composte da più campi. E qui subito mi domando: ma se alcuni
campi sono numerici ed altri alfanumerici potrò gestire la chiave
composta?
Per il momento mi sono creato del codice per calcolare la chiave
progressiva, non dovrei avere particolari problemi perché la quantità
di record da memorizzare è modesta con due o massimo tre client.
Grazie a tutti per il vostro aiuto.
Biagio