In quale caso usi l' @JoinTableannotazione JPA ?
In quale caso usi l' @JoinTableannotazione JPA ?
Risposte:
EDIT 2017-04-29 : Come sottolineato da alcuni dei commentatori, l' JoinTableesempio non ha bisogno mappedBydell'attributo annotation. In effetti, le versioni recenti di Hibernate si rifiutano di avviarsi stampando il seguente errore:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Facciamo finta di avere un'entità nominata Projecte un'altra entità nominataTask e che ogni progetto possa avere molte attività.
È possibile progettare lo schema del database per questo scenario in due modi.
La prima soluzione è creare una tabella denominata Projecte un'altra tabella denominata Taske aggiungere una colonna chiave esterna alla tabella attività denominata project_id:
Project Task
------- ----
id id
name name
project_id
In questo modo, sarà possibile determinare il progetto per ogni riga nella tabella delle attività. Se usi questo approccio, nelle tue classi di entità non avrai bisogno di una tabella di join:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
L'altra soluzione consiste nell'utilizzare una terza tabella, ad esempio Project_Tasks, e memorizzare la relazione tra progetti e attività in quella tabella:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
La Project_Taskstabella si chiama "Unisci tabella". Per implementare questa seconda soluzione in JPA è necessario utilizzare l' @JoinTableannotazione. Ad esempio, al fine di implementare un'associazione uno-a-molti unidirezionale, possiamo definire le nostre entità in quanto tali:
Project entità:
@Entity
public class Project {
@Id
@GeneratedValue
private Long pid;
private String name;
@JoinTable
@OneToMany
private List<Task> tasks;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}
Task entità:
@Entity
public class Task {
@Id
@GeneratedValue
private Long tid;
private String name;
public Long getTid() {
return tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Ciò creerà la seguente struttura del database:
L' @JoinTableannotazione consente inoltre di personalizzare vari aspetti della tabella di join. Ad esempio, avevamo annotato la tasksproprietà in questo modo:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
Il database risultante sarebbe diventato:
Infine, se si desidera creare uno schema per un'associazione molti-a-molti, l'utilizzo di una tabella di join è l'unica soluzione disponibile.
@JoinTable/@JoinColumnpossa essere annotato sullo stesso campo con mappedBy. Quindi l'esempio corretto dovrebbe essere mantenendo l' mappedByin Project, e spostare il @JoinColumnverso Task.project (o viceversa)
Project_Tasksha bisogno namedi Taskcosì, che diventa tre colonne: project_id, task_id, task_name, come raggiungere questo obiettivo?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
È anche più pulito da usare @JoinTable quando un'entità potrebbe essere il bambino in diverse relazioni padre / figlio con diversi tipi di genitori. Per dare seguito all'esempio di Behrang, immagina che un'attività possa essere figlia di Progetto, Persona, Dipartimento, Studio e Processo.
La tasktabella dovrebbe avere 5 nullablecampi chiave esterna? Penso di no...
È l'unica soluzione per mappare un'associazione ManyToMany: è necessaria una tabella di join tra le due tabelle entità per mappare l'associazione.
Viene anche utilizzato per le associazioni OneToMany (generalmente unidirezionali) quando non si desidera aggiungere una chiave esterna nella tabella dei molti lati e quindi mantenerla indipendente da un lato.
Cerca @JoinTable nella documentazione di ibernazione per spiegazioni ed esempi.
Ti consente di gestire la relazione Many to Many. Esempio:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Unisci tabella ti consente di creare una mappatura usando:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
creerà una tabella:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany associazioniMolto spesso, sarà necessario utilizzare l' @JoinTableannotazione per specificare la mappatura di una relazione di tabella molti-a-molti:
Quindi, supponendo di avere le seguenti tabelle del database:
Nella Postentità, si potrebbe mappare questa relazione, in questo modo:
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
L' @JoinTableannotazione viene utilizzata per specificare il nome della tabella tramite l' nameattributo, nonché la colonna Chiave esterna che fa riferimento alla posttabella (ad es. joinColumns) E la colonna Chiave esterna nella post_tagtabella dei collegamenti che fa riferimento Tagall'entità tramite l' inverseJoinColumnsattributo.
Si noti che l'attributo cascade
@ManyToManydell'annotazione è impostato suPERSISTeMERGEsolo perché il cascadingREMOVEè una cattiva idea poiché noi l'istruzione DELETE verrà emessa per l'altro record padre,tagnel nostro caso, non per ilpost_tagrecord. Per maggiori dettagli su questo argomento, consulta questo articolo .
@OneToManyAssociazioni unidirezionaliLe @OneToManyassociazioni unidirezionali , che mancano a@JoinColumn mappatura, si comportano come relazioni da molti a molti piuttosto che da uno a molti.
Quindi, supponendo che tu abbia i seguenti mapping di entità:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
//Constructors, getters and setters removed for brevity
}
Hibernate assumerà il seguente schema di database per il mapping delle entità sopra riportato:
Come già spiegato, la @OneToManymappatura unidirezionale JPA si comporta come un'associazione molti-a-molti.
Per personalizzare la tabella dei collegamenti, puoi anche utilizzare l' @JoinTableannotazione:
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JoinTable(
name = "post_comment_ref",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();
E ora verrà chiamata la tabella dei collegamenti post_comment_refe le colonne Chiave esterna saranno post_id, per la posttabella e post_comment_id, per la post_commenttabella.
Le
@OneToManyassociazioni unidirezionali non sono efficienti, quindi è meglio usare le@OneToManyassociazioni bidirezionali o solo il@ManyToOnelato. Consulta questo articolo per maggiori dettagli su questo argomento.