In welchem Fall verwenden Sie die JPA- @JoinTable
Annotation?
In welchem Fall verwenden Sie die JPA- @JoinTable
Annotation?
Antworten:
EDIT 2017-04-29 : Wie von einigen Kommentatoren erwähnt, benötigt das JoinTable
Beispiel das mappedBy
Annotation-Attribut nicht. Tatsächlich weigern sich neuere Versionen von Hibernate, den folgenden Fehler zu drucken:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Stellen wir uns vor, Sie haben eine Entität mit dem Namen Project
und eine andere Entität mit dem Namen Task
und jedes Projekt kann viele Aufgaben haben.
Sie können das Datenbankschema für dieses Szenario auf zwei Arten entwerfen.
Die erste Lösung besteht darin, eine Tabelle mit dem Namen Project
und eine andere Tabelle mit dem Namen zu erstellen und Task
der Aufgabentabelle mit dem Namen project_id
: eine Fremdschlüsselspalte hinzuzufügen.
Project Task
------- ----
id id
name name
project_id
Auf diese Weise kann das Projekt für jede Zeile in der Aufgabentabelle ermittelt werden. Wenn Sie diesen Ansatz verwenden, benötigen Sie in Ihren Entitätsklassen keine Join-Tabelle:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
Die andere Lösung besteht darin, eine dritte Tabelle zu verwenden, z. B. Project_Tasks
die Beziehung zwischen Projekten und Aufgaben in dieser Tabelle zu speichern:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Die Project_Tasks
Tabelle wird als "Join-Tabelle" bezeichnet. Um diese zweite Lösung in JPA zu implementieren, müssen Sie die @JoinTable
Anmerkung verwenden. Um beispielsweise eine unidirektionale Eins-zu-Viele-Zuordnung zu implementieren, können wir unsere Entitäten als solche definieren:
Project
Entität:
@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ät:
@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;
}
}
Dadurch wird die folgende Datenbankstruktur erstellt:
Mit der @JoinTable
Anmerkung können Sie auch verschiedene Aspekte der Verknüpfungstabelle anpassen. Hatten wir die tasks
Eigenschaft beispielsweise folgendermaßen kommentiert :
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
Die resultierende Datenbank wäre geworden:
Wenn Sie ein Schema für eine Viele-zu-Viele-Zuordnung erstellen möchten, ist die Verwendung einer Verknüpfungstabelle die einzige verfügbare Lösung.
@JoinTable/@JoinColumn
kann auf dem gleichen Feld mit kommentiert werden mappedBy
. Das richtige Beispiel sollte also sein, das mappedBy
In beizubehalten Project
und das @JoinColumn
zu Task.project
(oder umgekehrt) zu verschieben
Project_Tasks
die Bedürfnisse name
von Task
als auch, was drei Spalten wird: project_id
, task_id
, task_name
, wie dies zu erreichen?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Es ist auch sauberer zu verwenden, @JoinTable
wenn eine Entität das Kind in mehreren Eltern-Kind-Beziehungen mit verschiedenen Elterntypen sein kann. Stellen Sie sich vor, eine Aufgabe kann das Kind von Projekt, Person, Abteilung, Studie und Prozess sein, um Behrangs Beispiel zu verfolgen.
Sollte die task
Tabelle 5 nullable
Fremdschlüsselfelder enthalten? Ich denke nicht...
Dies ist die einzige Lösung zum Zuordnen einer ManyToMany-Zuordnung: Sie benötigen eine Verknüpfungstabelle zwischen den beiden Entitätstabellen, um die Zuordnung zuzuordnen.
Es wird auch für OneToMany-Zuordnungen (normalerweise unidirektional) verwendet, wenn Sie keinen Fremdschlüssel in die Tabelle der vielen Seiten einfügen und ihn somit unabhängig von der einen Seite halten möchten.
Suchen Sie in der Dokumentation zum Ruhezustand nach @JoinTable, um Erklärungen und Beispiele zu erhalten.
Damit können Sie mit vielen zu vielen Beziehungen umgehen. Beispiel:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Mit Join Table können Sie eine Zuordnung erstellen, indem Sie:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
erstellt eine Tabelle:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
VerbändeIn den meisten Fällen müssen Sie @JoinTable
Anmerkungen verwenden, um die Zuordnung einer Viele-zu-Viele-Tabellenbeziehung anzugeben:
Angenommen, Sie haben die folgenden Datenbanktabellen:
In der Post
Entität würden Sie diese Beziehung folgendermaßen zuordnen:
@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<>();
Die @JoinTable
Anmerkung wird verwendet, um den Tabellennamen über das name
Attribut sowie die Fremdschlüsselspalte anzugeben, die auf die Tabelle verweist post
(z. B. joinColumns
), und die Fremdschlüsselspalte in der post_tag
Verknüpfungstabelle, die Tag
über das inverseJoinColumns
Attribut auf die Entität verweist .
Beachten Sie, dass das Kaskadenattribut der
@ManyToMany
Annotation aufPERSIST
undMERGE
nur gesetzt ist, weil KaskadierungREMOVE
eine schlechte Idee ist, da die DELETE-Anweisung für den anderen übergeordneten Datensatz ausgegeben wird,tag
in unserem Fall nicht für denpost_tag
Datensatz. Weitere Informationen zu diesem Thema finden Sie in diesem Artikel .
@OneToMany
AssoziationenDie unidirektionalen @OneToMany
Assoziationen, denen eine @JoinColumn
Zuordnung fehlt , verhalten sich eher wie viele-zu-viele-Tabellenbeziehungen als wie eins-zu-viele.
Angenommen, Sie haben die folgenden Entitätszuordnungen:
@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
}
Der Ruhezustand übernimmt das folgende Datenbankschema für die obige Entitätszuordnung:
Wie bereits erläutert, @OneToMany
verhält sich die unidirektionale JPA-Zuordnung wie eine Viele-zu-Viele-Zuordnung.
Zum Anpassen der Verknüpfungstabelle können Sie auch die @JoinTable
Anmerkung verwenden:
@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<>();
Und jetzt wird die Verknüpfungstabelle aufgerufen post_comment_ref
und die Fremdschlüsselspalten werden post_id
für die post
Tabelle und post_comment_id
für die post_comment
Tabelle angezeigt.
Unidirektionale
@OneToMany
Assoziationen sind nicht effizient, daher ist es besser, bidirektionale@OneToMany
Assoziationen oder nur die@ManyToOne
Seite zu verwenden. In diesem Artikel finden Sie weitere Informationen zu diesem Thema.