JPA @OneToMany - > odniesienie rodzic-dziecko (klucz obcy)
[[11]] mam pytanie odnośnie odnoszenia się do rodziców od dziecka ir Jeśli mam coś takiego:
Rodzic.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> children;
simple ... getter and setter ...
}
I dziecko.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
@ManyToOne
private Parent parent;
... simple getter an setter
}
Zostaną utworzone następujące tabele:
Parent:
int id
Child:
int id
int parent_id (foreign key: parent.id)
Ok, jak na razie wszystko w porządku. Ale jeśli chodzi o Korzystanie z tego odniesienia z Javy, myślę, że można zrobić coś takiego.
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
Co prowadzi do tego w Bazie Danych:
Parent:
id
100
Child
id paren_id
101 100
Ale tak nie jest, masz aby wyjaśnić, ustawić rodzica na dziecko(co, jak sądzę, framework mógłby zrobić sam).
Więc co tak naprawdę w bazie jest to:
Parent:
id
100
Child
id paren_id
101 (null)
Bo nie ustawiłem rodzica na dziecko. Więc moje pytanie:
Czy naprawdę muszę robić sth. tak?
Rodzic.java:
...
setChildren(Set<Child> children) {
for (Child child : children) {
child.setParent.(this);
}
this.children = children;
}
...
Edit:
Zgodnie z szybkimi odpowiedziami udało mi się rozwiązać ten Problem za pomocą @ JoinColumn na podmiocie posiadającym odniesienie. Jeśli weźmiemy przykład z góry, zrobiłem sth. tak:
Rodzic.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name= "paren_id")
private Set<Child> children;
simple ... getter and setter ...
}
I dziecko.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
... simple getter an setter
}
Teraz jeśli zrobimy to:
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
Odniesienie jest poprawnie ustawione przez rodzica:
Parent:
id
100
Child
id paren_id
101 100
Dzięki za odpowiedzi.
5 answers
Czy naprawdę muszę robić sth. tak?To jedna ze strategii.
W relacjach dwukierunkowych istnieje strona" posiadająca "i" nie posiadająca " relacji. Ponieważ strona własności w Twoim przypadku jest na Child
, musisz ustawić tam relację, aby została utrzymana. Strona posiadania jest zwykle określana przez miejsce, w którym podajesz @JoinColumn
, ale nie wygląda na to, że używasz tej adnotacji, więc prawdopodobnie wywnioskujesz z faktu, że używany mappedBy
w adnotacji Parent
.
Możesz przeczytać o tym tutaj .
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
2018-03-12 12:54:06
Tak, tak jest. JPA nie dba o spójność wykresu encji. Szczególnie musisz ustawić go po stronie właściciela relacji dwukierunkowej (w Twoim przypadku na atrybut rodzic dziecka).
W specyfikacji JPA 2.0 jest to powiedziane następującymi słowami:
Zauważ, że to aplikacja ponosi odpowiedzialność za utrzymanie spójności relacji run-time-np., za zapewnienie, że "jedna" i "wiele" stron a bidi-rectional relacje są ze sobą zgodne, gdy zastosowanie aktualizuje relację w czasie wykonywania.
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
2012-03-02 12:59:51
/ Align = "left" / W rodzicu Entity
możesz mieć coś takiego
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
W celu uniknięcia powtarzania kodu do ustawiania relacji dziecko/rodzic w innym miejscu kodu.
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-11-22 12:44:58
Napotkaliśmy problem podczas utrzymywania prostego wykresu obiektów, takiego jak ten pokazany powyżej. Uruchamianie w H2 wszystko by działało, ale kiedy uruchomiliśmy się przeciwko MySQL ' owi, "paren_id" w tabeli potomnej (zdefiniowanej w adnotacji @JoinColumn) nie był wypełniany wygenerowanym id rodzica - nawet jeśli był ustawiony jako kolumna non-null z ograniczeniem klucza obcego w DB.
Dostalibyśmy wyjątek taki:
org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
Dla każdego, kto może natknąć się na to, co my w końcu okazało się, że musimy mieć inny atrybut @JoinColumn
, aby go uruchomić:
@JoinColumn(name="paren_id", nullable=false)
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
2018-04-19 20:29:07
Jeśli dobrze rozumiem, zgodnie z EntityManager
, jeśli chcesz, aby zarządzał zleceniem Wstawienia transakcji, musisz "powiedzieć mu", że powinno to również trwać dzieci. I nie robisz tego, więc " on "nie wie, co utrzymywać, ale lista Potomków twojego rodzica nie jest pusta, więc" on " bierze, że ma poprawną wartość, ale przechowywana wartość jest null.
Więc powinieneś rozważyć zrobienie czegoś takiego:
... begin, etc
em.persist(child)
em.persist(parent)
Zrób co chcesz z obiektem nadrzędnym tutaj następnie zatwierdź i to powinno działać dla podobne przypadki też.
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
2016-04-08 15:27:30