Je souhaite conserver l'entité parent avec 20 entités enfant, mon code est ci-dessous
Classe parent
@OneToMany(mappedBy = "parentId")
private Collection<Child> childCollection;
Classe enfant
@JoinColumn(name = "parent_id", referencedColumnName = "parent_id")
@ManyToOne(optional=false)
private Parent parent;
String jsonString = "json string containing parent properties and child collection"
ObjectMapper mapper = new ObjectMapper();
Parent parent = mapper.readValue(jsonString, Parent.class);
public void save(Parent parent) {
Collection<Child> childCollection = new ArrayList<>() ;
for(Child tha : parent.getChildCollection()) {
tha.setParent(parent);
childCollection.add(tha);
}
parent.setChildCollection(childCollection);
getEntityManager().persist(parent);
}
Donc, s'il y a 20 tables enfants, je dois définir la référence parent dans chacune d'elles pour que je dois écrire 20 pour les boucles? Est-ce faisable? y a-t-il une autre manière ou configuration où je peux automatiquement persister parent et enfant?
Fixez votre classe Parent:
@OneToMany(mappedBy = "parent")
La propriété mappedBy doit pointer vers un champ de l'autre côté de la relation. Comme JavaDoc dit:
Champ propriétaire de la relation. Obligatoire sauf si la relation est unidirectionnelle.
Vous devez également conserver explicitement l'entité enfant dans le cycle:
for(Child tha : parent.getChildCollection()) {
...
getEntityManager().persist(tha);
...
}
Comme Alan Hay l'a remarqué dans les commentaires, vous pouvez utiliser les fonctionnalités de cascade et laisser EntityManager automatiquement persister toutes vos entités enfants:
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
Plus de détails sur les cascades (et JPA lui-même) que vous pouvez trouver dans le blog de Vlad Mihalcea .
Généralement, @JoinColumn indique que l'entité est le propriétaire de la relation & mappedBy indique que l'entité est le inverse de la relation.
Donc, si vous essayez de suivre
@OneToMany(mappedBy = "parent")
private Collection<Child> childCollection;
Cela signifie qu'il est inverse de la relation et qu'il ne définira pas la référence parent à son enfant.
Pour définir la référence parent à son enfant, vous devez créer l'entité ci-dessus propriétaire de la relation de la manière suivante.
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn
private Collection<Child> childCollection;
Vous n'avez pas besoin de définir de référence enfant car le code ci-dessus créera une colonne dans la table enfant.
Comme indiqué dans les commentaires, vous devez veiller à la cohérence du graphe d'objet avec la relation enfant/parent. Cette cohérence ne sera pas gratuite lorsque JSON provient directement d'une demande POST.
Vous devez annoter le champ parent et enfant avec @JsonBackReference
Et @JsonManagedReference
.
Classe parent:
@OneToMany(mappedBy = "parentId")
@JsonBackReference
private Collection<Child> childCollection;
Classe enfant:
@JoinColumn(name = "parent_id", referencedColumnName = "parent_id")
@ManyToOne(optional=false)
@JsonManagedReference
private Parent parent;
Une question similaire avec réponse est ici
De plus, si vous utilisez @JsonBackReference
/@JsonManagedReference
Sur des classes annotées javax.persistence
En combinaison avec l'annotation @ToString
De Lombok, vous encourrez une erreur de débordement.
Excluez simplement les champs childCollection
et parent
de l'annotation @ToString
Avec @ToString( exclude = ...)
La même chose se produira avec la méthode equals()
générée par Lombok (@Data
, @EqualsAndHashCode
). Implémente simplement ces méthodes à la main ou pour utiliser uniquement les annotations @Getter
Et @Setter
.
Je laisserais le parent persister c'est ses propres enfants
package com.greg;
import Java.util.ArrayList;
import Java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
@Entity(name = "PARENT")
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "NAME")
private String name;
@Column(name = "DESCRIPTION")
private String description;
@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name = "parent", referencedColumnName = "id", nullable = false)
private List<Child> children = new ArrayList<Child>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
}