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.

Author: Sim0rn, 2012-03-02

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 .

 13
Author: beerbajay,
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.

 3
Author: Mikko Maunu,
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.

 1
Author: pirho,
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)
 1
Author: Phil Brock,
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ż.

 0
Author: João Rodrigues,
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