5.1 Varie forme di comunicazione uno a uno
C'è un altro caso interessante e piuttosto specifico di una relazione tra due classi Entity: una relazione uno a uno.
Chiamo questo caso molto specifico, poiché riguarda più gli oggetti Java che un database. Nel database, ci sono solo due opzioni per la relazione tra le tabelle:
- La riga della tabella contiene un collegamento all'id di un'altra tabella.
- La tabella dei servizi viene utilizzata per le relazioni molti-a-molti.
Nel caso delle classi di entità, potrebbero esserci opzioni descritte da diverse annotazioni:
- @Incorporato
- OneToOne unilaterale
- OneToOne bilaterale
- @MapsId
Di seguito considereremo il più popolare di loro.
5.2 Incorporato
A proposito, abbiamo già considerato l' opzione di comunicazione uno a uno@Embedded
più semplice: questa è un'annotazione . In questo caso, abbiamo due classi memorizzate nella stessa tabella nel database.
Supponiamo di voler memorizzare l'indirizzo dell'utente nella classe UserAddress :
@Embeddable
class UserAddress {
@Column(name="user_address_country")
public String country;
@Column(name="user_address_city")
public String city;
@Column(name="user_address_street")
public String street;
@Column(name="user_address_home")
public String home;
}
Quindi dobbiamo solo aggiungere un campo con questo indirizzo alla classe User :
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Hibernate farà il resto: i dati verranno archiviati in una tabella, ma quando si scrivono query HQL, sarà necessario operare sui campi di classe.
Esempio di query HQL:
select from User where address.city = 'Paris'
5.3 OneToOne unilaterale
Immagina ora la situazione: abbiamo una tabella di origine dipendente e un'attività che fa riferimento a dipendente. Ma sappiamo per certo che è possibile assegnare al massimo un'attività a un utente. Poi possiamo usare l'annotazione per descrivere questa situazione @OneToOne
.
Esempio:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@OneToOne
@JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
Hibernate farà in modo che non solo un'attività abbia un utente, ma anche che un utente abbia una sola attività. Altrimenti, questo caso non è praticamente diverso da @ManyToOne
.
5.4 OneToOne bilaterale
L'opzione precedente può essere un po' scomoda, perché spesso si desidera assegnare un dipendente non solo a un'attività, ma anche assegnare un'attività a un dipendente.
Per fare ciò, puoi aggiungere il campo EmployeeTask alla classe Employee e assegnargli le annotazioni corrette.
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
private EmployeeTask task;
}
Importante!La tabella dei dipendenti non ha un campo task_id , invece il campo employee_id della tabella delle attività viene utilizzato per stabilire una relazione tra le tabelle .
Stabilire una connessione tra oggetti è simile a questo:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
session.update(task);
session.flush();
Per rimuovere il collegamento, è necessario rimuovere anche i collegamenti da entrambi gli oggetti:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
task.employee = null;
session.update(task);
director.task = null;
session.update(director);
session.flush();