2012-03-02 8 views
37

Ho una domanda sul riferimento ParentEntities da bambino entités ir Se ho qualcosa di simile:JPA @OneToMany -> Parent - Bambino di riferimento (chiave esterna)

Parent.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 ... 
} 

e il Child.java:

@Entity(name ="Child") 
public class Child{ 
    @Id 
    @Generate.... 
    @Column 
    private int id; 

    @ManyToOne 
    private Parent parent; 

    ... simple getter an setter 
} 

seguenti tabelle stanno per essere creati:

Parent: 
    int id 

Child: 
    int id 
    int parent_id (foreign key: parent.id) 

Ok, finora tutto bene. Ma quando si tratta di utilizzare questo riferimento da Java, penserei, si può fare qualcosa di simile.

@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); 
    } 

che porta a questo nella risorsa:

Parent: 
    id 
    100 

Child 
    id  paren_id 
    101 100 

Ma non questo è il caso, si deve esplicitamente impostare la Capogruppo al Bambino (che, pensavo, il quadro potrebbe probabilmente fare da si).

Così che cosa è realmente nel database è questo:

Parent: 
    id 
    100 

Child 
    id  paren_id 
    101 (null) 

causa non ho impostato il padre al bambino. Quindi la mia domanda:

Devo davvero fare sth. come questo?

Parent.java:

... 
setChildren(Set<Child> children) { 
    for (Child child : children) { 
    child.setParent.(this); 
    } 

    this.children = children; 
} 
... 

Edit:

In base alle risposte veloci sono stato in grado di risolvere questo problema utilizzando il @JoinColumn sul Entità di Riferimento-Possedere. Se prendiamo l'esempio dall'alto, ho fatto sth. in questo modo:

Parent.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 ... 
    } 

E il Child.java:

@Entity(name ="Child") 
public class Child{ 
    @Id 
    @Generate.... 
    @Column 
    private int id; 

    ... simple getter an setter 
} 

Ora, se facciamo questo:

@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); 
    } 

Il riferimento è correttamente impostato il genitore:

Parent: 
    id 
    100 

Child 
    id  paren_id 
    101 100 

Grazie per le risposte.

+0

** hai un genitore sull'entità figlio? ** se sì come hanno configurato.Con nessun genitore ottengo l'errore (_StaleStateException: L'aggiornamento batch ha restituito il conteggio delle righe inatteso dall'aggiornamento [0], il conteggio delle righe effettivo: 0; previsto: 1_). Se aggiungo un genitore senza annotazioni mostra anche l'errore (errore di mappatura). Con l'impostazione @manytoone sul campo padre di child ottengo l'errore su save (_ORA-00904: "REPORT_REPORT_ID": недопустимый идентификатор_). il mio fk e il suo pk su id hanno chiamato report_id ma non so da dove viene report_report_id. – Erlan

+0

(Utilizzo dell'implementazione JPA di EclipseLink). Vale la pena notare che è ancora necessario il parenId privato lungo @Column (name = "paren_id"); mappatura su tuo figlio per questo lavoro. – AfterWorkGuinness

risposta

12

Devo davvero fare sth. come questo?

Questa è una strategia, sì.

Nelle relazioni bidirezionali esiste un lato "proprietario" e un "non proprietario" della relazione. Poiché il lato proprietario nel tuo caso è Child, è necessario impostare la relazione in modo che venga mantenuta. Il lato proprietario viene in genere determinato da dove si specifica @JoinColumn, ma non sembra che si stia utilizzando quell'annotazione, quindi è probabile che venga dedotto dal fatto che si è utilizzato mappedBy nell'annotazione Parent.

È possibile read a lot more about this here.

3

Sì, questo è il caso. JPA non si preoccupa della coerenza del grafico delle entità. Soprattutto devi impostarlo sul lato proprietario della relazione bidirezionale (nel tuo caso con l'attributo genitore di Child).

In JPA 2.0 specifica questo è detto con queste parole:

Si noti che è l'applicazione che ha la responsabilità di mantenere la coerenza dei rapporti di runtime, ad esempio, per assicurare che “uno” e “molti "I lati di una relazione bifunzionale sono coerenti tra loro quando l'applicazione aggiorna la relazione in fase di runtime.

1

Si è verificato un problema mentre persisteva un semplice oggetto grafico come quello mostrato sopra. Eseguendo in H2 tutto funzionerebbe, ma quando abbiamo corso contro MySQL il "paren_id" nella tabella figlio (definito nell'annotazione @JoinColumn) non veniva popolato con l'id generato del genitore - anche se era impostato come non -nulla colonna con un vincolo di chiave esterna nel DB.

Ci piacerebbe ottenere un'eccezione in questo modo:

org.hibernate.exception.GenericJDBCException: Il campo 'paren_id' non ha un valore predefinito

Per chiunque altro che potrebbe incorrere in questo, che cosa abbiamo finalmente trovato era che abbiamo dovuto a un altro attributo al @JoinColumn per farlo funzionare:

@JoinColumn (name = "paren_id", nullable = false)

0

Se io vi sto ottenendo correttamente, in base alle EntityManager, se lo sei vuoi che gestisca l'ordine di inserimento della transazione che devi "dirgli" che dovrebbe persistere anche nei bambini. E tu non lo stai facendo, quindi "lui" non sa cosa persistere, ma l'elenco figlio del tuo genitore non è vuoto, quindi "lui" lo considera corretto ma il valore memorizzato è nullo.

così si dovrebbe prendere in considerazione fare qualcosa di simile:

... begin, etc 
em.persist(child) 
em.persist(parent) 

fare ciò che si vuole con l'oggetto principale qui poi impegnarsi e questo dovrebbe funzionare per casi simili anche.

1

Sembra ancora che sia il caso. In genitore Entity si può avere qualcosa di simile

@PrePersist 
private void prePersist() { 
    children.forEach(c -> c.setParent(this)); 
} 

al fine di evitare di ripetere il codice per l'impostazione relazione figlio/genitore altrove in codice.

+0

!! bel uomo dopo mi sono bloccato alomost 2 settimane. provo a mandare json dal client e convertire in oggetto usando @RequestBody di primavera quindi salvare in db non voglio gestire la relazione da parte mia (imposta genitore a figlio - non ha senso per me) – WRDev

+0

!!! aggiornare !!! link su @PrePersist (puoi gestirlo con @EntityListener) vedi - https://www.concretepage.com/java/jpa/jpa-entitylisteners-example-with-callbacks-prepersist-postpersist-postload-preupdate-postupdate -preremove-postremove – WRDev