Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 22 di 68
  • livello ninja
Indice lezioni

JPA: relazioni uno a uno tra Entity

Come definire relazioni uno ad uno unidirezionali e bidirezionali tra Entity con la Java Persistence API.
Come definire relazioni uno ad uno unidirezionali e bidirezionali tra Entity con la Java Persistence API.
Link copiato negli appunti

Finora abbiamo visto come mappare singole Entity su una tabella. Le tabelle sono in genere relazionate tramite vincoli di foreign key con cui associare un record di una tabella ad uno o più record di un'altra (relazioni uno a uno e uno a molti), o più record di una tabella con diversi record di un'altra (molti a molti).

Gli stessi tipi di relazione si definiscono tra Entity con l'aggiunta, grazie al persistence provider, della direzionalità che specifica relazioni unidirezionali o bidirezionali.

Relazioni OneToOne

Iniziamo affrontando la più semplice delle relazioni: uno a uno, questo tipo di relazione è presente tra le Entity Booking e Room. In sostanza stiamo dicendo che ad una prenotazione (Booking) è associata una singola stanza (Room).

Supponiamo di trovarci nel caso in cui il database sia già esistente e che le tabelle relazionali siano le seguenti:

Figura 1. Relazione uno a uno Bidirezionale
Relazione uno a uno bidirezionale

Abbiamo due tabelle legate da un vincolo di foreign key che va BOOKING a ROOM. Le chiavi primarie delle due tabelle hanno il medesimo nome: ID, ipotizziamo inoltre che siano state definite le sequenze BOOKING_SEQUENCE e ROOM_SEQUENCE per generare i valori delle chiavi.

Utilizziamo quanto appreso nper realizzare le entity Booking e Room legate alle tabelle e creiamole all'interno di it.html.model.hotel del progetto ProgettoJpa1:

@Entity
@Table(name="BOOKING")
@SequenceGenerator(name="BOOKING_GENERATOR",
				   sequenceName="BOOKING_SEQUENCE")
public class Booking {
	private long id;
	private float amount;
	private Date  checkIn;
	private Date  checkOut;
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE,
					generator="BOOKING_GENERATOR")
	@Column(name="ID")
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	@Column(name="AMOUNT")
	public float getAmount() {
		return amount;
	}
	public void setAmount(float amount) {
		this.amount = amount;
	}
	@Column(name="CHECK_IN")
	@Temporal(TemporalType.DATE)
	public Date getCheckIn() {
		return checkIn;
	}
	public void setCheckIn(Date checkIn) {
		this.checkIn = checkIn;
	}
	@Column(name="CHECK_OUT")
	@Temporal(TemporalType.DATE)
	public Date getCheckOut() {
		return checkOut;
	}
	public void setCheckOut(Date checkOut) {
		this.checkOut = checkOut;
	}
}

@Entity
@Table(name="ROOM")
@SequenceGenerator(name="ROOM_GENERATOR",
 				   sequenceName="ROOM_SEQUENCE")
public class Room {
	private long id;
	private int num;
	private String type;
	private String free;
	private Booking booking;
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE,
				 	generator="ROOM_GENERATOR")
	@Column(name="ID")
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	@Column(name="NUM")
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	@Column(name="TYPE")
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	@Column(name="FREE")
	public String getFree() {
		return free;
	}
	public void setFree(String free) {
		this.free = free;
	}
	@OneToOne(mappedBy="room")
	public Booking getBooking() {
		return booking;
	}
	public void setBooking(Booking booking) {
		this.booking = booking;
	}
}

Abbiamo quindi legato l'Entity alla tabella grazie all'annotation @Table ed utilizzato @Column per specificare il mapping con le colonne della tabella. Con @SequenceGenerator e @GeneratedValue abbiamo infine collegato le sequenze.

Inseriamo ora una relazione OneToOne bidirezionale
sulla base del vincolo di foreign key. In una relazione bidirezionale ogni lato della relazione
è a conoscenza dell'altro, questo si traduce nella presenza di un campo Room nella classe Booking e un campo
Booking nella classe Room: la relazione è navigabile da entrambe le direzioni.

Aggiungiamo quindi il seguente codice nella classe Booking per le annotazioni @OneToOne e @JoinColumn:

private Room room;
 	@OneToOne
	@JoinColumn(name="ROOM_ID")
	public Room getRoom() {
		return room;
	}
	public void setRoom(Room room) {
		this.room = room;
	}

Con @OneToOne informiamo il persistence provider della relazione Booking-Room nel verso indicato, specificando come colonna Join di BOOKING il campo ROOM_ID. Inseriamo ora all'interno di Room:

private Booking booking;
@OneToOne(mappedBy="room")
public Booking getBooking() {
		return booking;
}
public void setBooking(Booking booking) {
		this.booking = booking;
}

Data una stanza siamo quindi in grado di capire se è oggetto di una prenotazione.

Lato owner e lato inverso

A differenza di Booking in @OneToOne di Room abbiamo specificato l'attributo mappedBy, infatti
una relazione bidirezionale porta con sé il concetto di lato owner e lato inverso. owner è l'Entity
la cui annotation di relazione (@OneToOne) non specifica il mappedBy. In sostanza, per una relazione
bidirezionale è sempre l'entity collegata alla tabella che detiene il vincolo relazionale di foreign key

Il lato inverso indica esattamente questa informazione ("non sono io l'Owner, guarda l'altra l'entity indicata") inserendo nell'attributo mappedBy il nome del campo relazione nell'entity opposta (room dell'entity Booking).

La relazione OneToOne unidirezionale è possibile specificando l'annotation @OneToOne soltanto su uno dei due lati (Owner) senza utilizzare mappedBy, cosi ad esempio la unidirezionale lato Entity Booking, si traduce in:

private Room room;
 	@OneToOne
	@JoinColumn(name="ROOM_ID")
	public Room getRoom() {
		return room;
	}
	public void setRoom(Room room) {
		this.room = room;
	}

Se volessimo invece una relazione unidirezionale lato Room inseriremmo nell'Entity Room:

private Booking booking;
 	@OneToOne
	@JoinColumn(name="ROOM_ID")
	public Booking getBooking() {
		return booking;
	}
	public void setBooking(Booking booking) {
		this.booking = booking;
	}

rimuovendo la relazione OneToOne in Booking.

ROOM_ID è sempre il campo definito in BOOKING. Nel caso unidirezionale, all'unica Entity Owner che contiene l'annotation di relazione non corrisponde necessariamente la tabella relazionale con il vincolo di foreign key. L'Owner di una relazione deve corrispondere alla tabella con il foreign key soltanto nel caso bidirezionale.

Ti consigliamo anche