Jaka jest różnica między @JoinColumn a mappedBy przy użyciu asocjacji JPA @OneToMany
Jaka jest różnica między:
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
private List<Branch> branches;
...
}
I
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
private List<Branch> branches;
...
}
8 answers
Adnotacja @JoinColumn
wskazuje, że encja ta jestwłaścicielem relacji (to znaczy: odpowiednia tabela ma kolumnę z kluczem obcym do tabeli odniesienia), podczas gdy atrybut mappedBy
wskazuje, że encja po tej stronie jest odwrotnością relacji, a właściciel rezyduje w "innym" encji. Oznacza to również, że możesz uzyskać dostęp do drugiej tabeli z klasy, do której dodałeś adnotację "mappedBy" (w pełni dwukierunkowa relacja).
W w szczególności, dla kodu w pytaniu poprawne adnotacje wyglądałyby tak:
@Entity
public class Company {
@OneToMany(mappedBy = "company",
orphanRemoval = true,
fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private List<Branch> branches;
}
@Entity
public class Branch {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "companyId")
private Company company;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-04 21:58:56
@JoinColumn
może być stosowany po obu stronach związku. pytanie dotyczyło użycia {[2] } Po Stronie @OneToMany
(rzadki przypadek). Chodzi o powielanie informacji fizycznych (Nazwa kolumny) wraz z nie zoptymalizowanym zapytaniem SQL, które wytworzy dodatkowe UPDATE
instrukcje .
Według dokumentacji :
Ponieważ wiele do jednego to (prawie) zawsze strona właściciela relacji dwukierunkowej w JPA Spec, Stowarzyszenie jeden do wielu jest adnotowane przez @OneToMany(mappedBy=...)
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
Troop
ma dwukierunkową relację jeden do wielu z Soldier
poprzez własność wojsk. Nie musisz (nie musisz) definiować żadnego fizycznego mapowania po stronie mappedBy
.
Aby odwzorować dwukierunkowy jeden do wielu, z jeden do wielu jako strona posiadająca , musisz usunąć mappedBy
element i ustawić wiele na jeden @JoinColumn
jako insertable
i updatable
NA false. To rozwiązanie nie jest zoptymalizowane i będzie Utwórz dodatkowe UPDATE
stwierdzenia.
@Entity
public class Troop {
@OneToMany
@JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-26 07:59:16
Jednokierunkowe skojarzenie jeden do wielu
Jeśli używasz adnotacji @OneToMany
z @JoinColumn
, to masz jednokierunkowe skojarzenie, takie jak to między jednostką rodzica Post
a dzieckiem PostComment
na poniższym diagramie:
Przy użyciu jednokierunkowego skojarzenia jeden do wielu, tylko Strona nadrzędna mapuje skojarzenie.
W tym przykładzie tylko Post
byt zdefiniuje @OneToMany
związek z dzieckiem PostComment
entity:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();
Dwukierunkowe skojarzenie jeden do wielu
Jeśli używasz @OneToMany
z zestawem atrybutów mappedBy
, masz dwukierunkowe skojarzenie. W naszym przypadku zarówno encja Post
ma zbiór PostComment
jednostek potomnych, jak i encja potomna PostComment
ma odniesienie z powrotem do encji rodzica Post
, Jak pokazano na poniższym diagramie:
W encji PostComment
właściwość encji post
jest mapowana jako następuje:
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
Powodem, dla którego wyraźnie ustawiliśmy atrybut
fetch
naFetchType.LAZY
, jest to, że domyślnie wszystkie skojarzenia@ManyToOne
i@OneToOne
są pobierane chętnie, co może powodować N+1 problemy z zapytaniem.
W encji Post
Asocjacja comments
jest odwzorowana w następujący sposób:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
Atrybut mappedBy
adnotacji @OneToMany
odwołuje się do właściwości post
w encji potomka PostComment
i w ten sposób Hibernate wie, że dwukierunkowe skojarzenie jest kontrolowane przez Strona @ManyToOne
, która odpowiada za zarządzanie wartością kolumny klucza obcego, na której opiera się ta relacja tabeli.
Dla skojarzenia dwukierunkowego, musisz również mieć dwie metody użytkowe, takie jak addChild
i removeChild
:
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
Te dwie metody zapewniają, że obie strony dwukierunkowego skojarzenia są zsynchronizowane. Bez synchronizacji obu końców Hibernate nie gwarantuje, że zmiany stanu asocjacji będą propagowane do bazy danych.
Który z nich wybrać?
Jednokierunkowe skojarzenie @OneToMany
nie działa zbyt dobrze, więc powinieneś tego unikać.
Lepiej używać dwukierunkowego @OneToMany
, który jest bardziej wydajny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-08 21:02:33
Adnotacja mappedBy idealnie powinna być zawsze używana w stronie nadrzędnej (klasie firmowej) relacji dwukierunkowej, w tym przypadku powinna być w klasie firmowej wskazując na zmienną członkowską "company" klasy potomnej (Branch class)
Adnotacja @ JoinColumn jest używana do określenia zmapowanej kolumny do dołączenia do asocjacji encji, ta adnotacja może być używana w dowolnej klasie (Rodzicu lub dziecku), ale powinna być używana tylko po jednej stronie (albo w Klasa rodzica lub w klasie potomnej Nie w obu) tutaj w tym przypadku użyłem go w stronie potomnej (klasie gałęzi) relacji dwukierunkowej wskazującej klucz obcy w klasie gałęzi.
Poniżej znajduje się roboczy przykład:
Klasa rodzica, firma
@Entity
public class Company {
private int companyId;
private String companyName;
private List<Branch> branches;
@Id
@GeneratedValue
@Column(name="COMPANY_ID")
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
@Column(name="COMPANY_NAME")
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
Klasa dziecięca, Oddział
@Entity
public class Branch {
private int branchId;
private String branchName;
private Company company;
@Id
@GeneratedValue
@Column(name="BRANCH_ID")
public int getBranchId() {
return branchId;
}
public void setBranchId(int branchId) {
this.branchId = branchId;
}
@Column(name="BRANCH_NAME")
public String getBranchName() {
return branchName;
}
public void setBranchName(String branchName) {
this.branchName = branchName;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COMPANY_ID")
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 10:23:01
Nie zgadzam się z przyjętą tu odpowiedzią Óscara Lópeza. Ta odpowiedź jest niedokładna!
Nie jest to @JoinColumn
, co wskazuje, że podmiot ten jest właścicielem związku. Zamiast tego robi to adnotacja @ManyToOne
(w jego przykładzie).
Adnotacje dotyczące relacji, takie jak @ManyToOne
, @OneToMany
i @ManyToMany
powiedz JPA / Hibernate, aby utworzyło mapowanie. domyślnie odbywa się to poprzez oddzielne połączenie Stolik.
@JoinColumn
Celem
@JoinColumn
jest utworzenie kolumny join , jeśli jeszcze nie istnieje. Jeśli tak, to ta adnotacja może być użyta do nazwa kolumny join.
MappedBy
Celem parametru
MappedBy
jest polecenie JPA: nie Utwórz inną tabelę join, gdy relacja jest już mapowana by the opposite podmiot tego związku.
Remember: {[8] } jest właściwością adnotacji relacji, której celem jest wygenerowanie mechanizmu do powiązania dwóch encji, które domyślnie robią tworząc tabelę join. MappedBy
zatrzymuje ten proces w jednym kierunku.
Encja nie używająca MappedBy
mówi się, że jest właścicielem relacji, ponieważ mechanika mapowania jest podyktowana w jej klasie poprzez użycie jednego z trzech mapowań adnotacje względem pola klucza obcego. To nie tylko określa charakter mapowania, ale także instruuje Tworzenie tabeli join. Co więcej, opcja wyłączania tabeli join istnieje również poprzez zastosowanie adnotacji @ JoinColumn nad kluczem obcym, który utrzymuje ją wewnątrz tabeli podmiotu właściciela.
Tak w podsumowaniu: @JoinColumn
albo tworzy nową kolumnę join albo zmienia nazwę istniejącej; podczas gdy parametr MappedBy
współpracuje z relacją adnotacje drugiej klasy (potomnej) w celu utworzenia mapowania przez tabelę join lub przez utworzenie kolumny klucza obcego w powiązanej tabeli podmiotu właściciela.
Aby zilustrować jak działa MapppedBy
, rozważ poniższy kod. Jeśli parametr MappedBy
miałby zostać usunięty, wtedy Hibernate utworzyłby dwie tabele join! Dlaczego? Ponieważ w relacjach wielu do wielu istnieje symetria, a Hibernate nie ma uzasadnienia dla wyboru jednego kierunku nad drugim.
We dlatego użyj MappedBy
aby powiedzieć Hibernate, wybraliśmy Inne entity do dyktowania odwzorowania relacji między dwoma podmiotami.
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
private List<Drivers> drivers;
}
Dodanie @JoinColumn (name = "driverID") w klasie właściciela (patrz poniżej) uniemożliwi utworzenie tabeli join i zamiast tego utworzy kolumnę klucza obcego driverID w tabeli Cars, aby utworzyć mapowanie:
@Entity
public class Driver {
@ManyToMany(mappedBy = "drivers")
private List<Cars> cars;
}
@Entity
public class Cars {
@ManyToMany
@JoinColumn(name = "driverID")
private List<Drivers> drivers;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-01 01:56:42
Chciałbym tylko dodać, że @JoinColumn
nie zawsze musi być związane z fizyczną lokalizacją informacji, Jak sugeruje to ta odpowiedź. Możesz połączyć @JoinColumn
z @OneToMany
, nawet jeśli tabela rodzica nie ma danych tabeli wskazujących na tabelę potomną.
Jak zdefiniować jednokierunkową relację OneToMany w JPA
Jednokierunkowa Onetomania, Brak Manytoonu Odwrotnego, BRAK Tabeli Join
Wydaje się, że jest dostępny tylko wJPA 2.x+
. Jest to przydatne w sytuacjach, w których chcesz, aby Klasa dziecięca zawierała tylko identyfikator rodzica, a nie pełne odniesienie.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:27
JPA jest warstwowym API, różne poziomy mają swoje własne adnotacje. Najwyższym poziomem jest (1) poziom encji, który opisuje trwałe klasy, następnie masz (2) poziom relacyjnej bazy danych, który zakłada, że encje są mapowane do relacyjnej bazy danych i (3) Model java.
Przypisy poziomu 1: @Entity
, @Id
, @OneToOne
, @OneToMany
, @ManyToOne
, @ManyToMany
.
Możesz wprowadzić trwałość w swojej aplikacji, używając tylko tych adnotacji wysokiego poziomu. Ale potem musisz stworzyć swój bazy danych zgodnie z założeniami JPA. Te adnotacje określają model entity / relationship.
Przypisy poziomu 2: @Table
, @Column
, @JoinColumn
, ...
Wpływaj na mapowanie z encji/właściwości do relacyjnych tabel/kolumn bazy danych, jeśli nie jesteś zadowolony z domyślnych wartości JPA lub jeśli musisz zmapować do istniejącej bazy danych. Te adnotacje mogą być postrzegane jako adnotacje implementacji, określają one sposób mapowania.
Moim zdaniem najlepiej trzymać jak najwięcej do adnotacji wysokiego poziomu, a następnie wprowadzić adnotacje niższego poziomu w razie potrzeby.
Aby odpowiedzieć na pytania:@OneToMany
/mappedBy
jest najładniejsza, ponieważ używa tylko adnotacji z domeny encji. Na @oneToMany
/@JoinColumn
jest również w porządku, ale używa adnotacji implementacji tam, gdzie nie jest to bezwzględnie konieczne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-26 08:49:24
Pozwól mi to uprościć.
Możesz użyć @JoinColumn po obu stronach, niezależnie od mapowania.
1) jednokierunkowe mapowanie od oddziału do firmy.
2) mapowanie dwukierunkowe od firmy do oddziału.
3) tylko jednokierunkowe mapowanie od firmy do oddziału.
Więc każdy przypadek użycia będzie należał do tych trzech kategorii. Pozwól mi więc wyjaśnić, jak używać @JoinColumni mappedBy.
1) Mapowanie jednokierunkowe od oddziału do firmy.
Użyj JoinColumn w tabeli gałęzi.
2) mapowanie dwukierunkowe od firmy do oddziału.
Użyj mappedBy w tabeli firm zgodnie z odpowiedzią @ Mychajło Adamowycz.
3) jednokierunkowe mapowanie od firmy do oddziału.
Wystarczy użyć @JoinColumn w tabeli firm.
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name="courseId")
private List<Branch> branches;
...
}
To mówi, że w oparciu o mapowanie klucza obcego "courseId" w tabeli branches, uzyskam listę wszystkich branches. Uwaga: nie możesz pobrać firma z oddziału w tym przypadku istnieje tylko jednokierunkowe mapowanie od firmy do oddziału.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-17 07:53:45