W jakim przypadku używasz @JoinTableadnotacji JPA ?
W jakim przypadku używasz @JoinTableadnotacji JPA ?
Odpowiedzi:
EDYCJA 2017-04-29 : Jak zauważyli niektórzy komentatorzy, JoinTableprzykład nie potrzebuje mappedByatrybutu adnotacji. W rzeczywistości najnowsze wersje Hibernacji odmawiają uruchomienia, wyświetlając następujący błąd:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Załóżmy, że masz jednostkę o nazwie Projecti inną o nazwie, Taska każdy projekt może mieć wiele zadań.
Schemat bazy danych można zaprojektować dla tego scenariusza na dwa sposoby.
Pierwszym rozwiązaniem jest utworzenie tabeli o nazwie Projecti innej tabeli o nazwie Taski dodanie kolumny klucza obcego do tabeli zadań o nazwie project_id:
Project Task
------- ----
id id
name name
project_id
W ten sposób będzie można określić projekt dla każdego wiersza w tabeli zadań. Jeśli używasz tego podejścia, w klasach encji nie będziesz potrzebować tabeli łączenia:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
Innym rozwiązaniem jest użycie np. Trzeciej tabeli Project_Tasksi zapisanie relacji między projektami i zadaniami w tej tabeli:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Project_TasksTabela nazywa się „Join Table”. Aby wdrożyć to drugie rozwiązanie w JPA, musisz użyć @JoinTableadnotacji. Na przykład, aby zaimplementować jednokierunkowe powiązanie jeden do wielu, możemy zdefiniować nasze jednostki jako takie:
Project jednostka:
@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 jednostka:
@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;
}
}
Spowoduje to utworzenie następującej struktury bazy danych:
@JoinTableAdnotacji pozwala również dostosować różne aspekty tabeli sprzężenia. Na przykład, gdybyśmy opisali taskswłaściwość w ten sposób:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
Powstała baza danych stałaby się:
Wreszcie, jeśli chcesz utworzyć schemat dla asocjacji wiele do wielu, użycie tabeli łączenia jest jedynym dostępnym rozwiązaniem.
@JoinTable/@JoinColumnw tym samym polu można umieścić adnotację mappedBy. Tak więc poprawnym przykładem powinno być trzymanie mappedByw Projectśrodku i przejście @JoinColumndo Task.project (lub odwrotnie)
Project_Taskspotrzebuje nameod Taska także, co staje się trzy kolumny: project_id, task_id, task_name, jak to osiągnąć?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Jest również bardziej przejrzysty w użyciu, @JoinTablegdy jednostka może być dzieckiem w kilku relacjach rodzic / dziecko z różnymi typami rodziców. Kontynuując przykład Behranga, wyobraź sobie, że zadanie może być dzieckiem projektu, osoby, działu, badania i procesu.
Czy tasktabela powinna mieć 5 nullablepól kluczy obcych? Myślę, że nie...
Jest to jedyne rozwiązanie umożliwiające mapowanie asocjacji ManyToMany: do mapowania powiązania potrzebna jest tabela łączenia między dwiema tabelami encji.
Jest również używany do asocjacji OneToMany (zwykle jednokierunkowych), gdy nie chcesz dodawać klucza obcego w tabeli wielu stron, a tym samym utrzymywać go niezależnie od jednej strony.
Wyszukaj @JoinTable w dokumentacji hibernacji, aby znaleźć wyjaśnienia i przykłady.
To pozwala ci radzić sobie w relacjach Wiele do wielu. Przykład:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Join Table umożliwia tworzenie mapowań przy użyciu:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
utworzy tabelę:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany wspomnieniaNajczęściej będziesz musiał użyć @JoinTableadnotacji, aby określić mapowanie relacji wiele do wielu tabel:
Więc zakładając, że masz następujące tabele bazy danych:
W Postencji można zmapować tę relację w następujący sposób:
@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<>();
@JoinTableAdnotacja jest używana do określenia nazwy tabel za pomocą nameatrybutu, a także kolumny klucza obcego która odwołuje się do posttabeli (na przykład joinColumns), a kolumna klucz obcy w post_tagtabeli połączeń, która odwołuje się Tagpodmiot za pośrednictwem inverseJoinColumnsatrybutu.
Zauważ, że atrybut kaskady
@ManyToManyadnotacji jest ustawiony naPERSISTiMERGEtylko dlatego, że kaskadowanieREMOVEjest złym pomysłem, ponieważ instrukcja DELETE zostanie wydana dla innego rekordu nadrzędnego,tagw naszym przypadku, a nie dlapost_tagrekordu. Więcej informacji na ten temat znajdziesz w tym artykule .
@OneToManyAsocjacje jednokierunkowe@OneToManySkojarzenia jednokierunkowe , którym brakuje @JoinColumnodwzorowania, zachowują się jak relacje między tabelami wiele do wielu, a nie jeden do wielu.
Więc zakładając, że masz następujące mapowania encji:
@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 przyjmie następujący schemat bazy danych dla powyższego mapowania encji:
Jak już wyjaśniono, jednokierunkowe @OneToManymapowanie JPA zachowuje się jak asocjacja wiele do wielu.
Aby dostosować tabelę linków, możesz również użyć @JoinTableadnotacji:
@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<>();
A teraz zostanie wywołana tabela linków, post_comment_refa kolumny klucza obcego będą post_iddla posttabeli i post_comment_iddla post_commenttabeli.
@OneToManyPowiązania jednokierunkowe nie są wydajne, więc lepiej jest używać@OneToManyasocjacji dwukierunkowych lub tylko@ManyToOnebocznych. Zapoznaj się z tym artykułem, aby uzyskać więcej informacji na ten temat.