JPA One-to-Two Persistent Parent and Child

I want to save a parent with 20 children, my code is below

Parent class

@OneToMany(mappedBy = "parentId") private Collection<Child> childCollection; 

Children class

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

So, if there are 20 child tables, then I have to set a parent link in each of them, because I need to write 20 for loops? Is it possible? is there any other way or configuration where i can automatically save parent and child elements?

+7
jpa one-to-many
source share
4 answers

Fix the parent class:

 @OneToMany(mappedBy = "parent") 
Property

mappedBy should point to a field on the other side of the relationship. As JavaDoc says:

The field to which the relation belongs. Required if the relation is not unidirectional.

You must also explicitly save the child in a loop:

 for(Child tha : parent.getChildCollection()) { ... getEntityManager().persist(tha); ... } 

As Alan Hay noted in the comment, you can use cascading objects and let EntityManager automatically save all child objects:

 @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST) 

More information about the cascades (and the JPA itself) can be found on the blog of Vlad Mikhalch .

+5
source share

Typically, @JoinColumn indicates that the object is the owner of the relationship , and mappedBy indicates that the object is the inverse of the relation .

So, if you are trying to follow the following

 @OneToMany(mappedBy = "parent") private Collection<Child> childCollection; 

This means that it is inverse to the relation , and it will not establish a parent link to its child.

To establish a parent link to its child, you must make the above object the owner of the relationship as follows.

 @OneToMany(cascade = CascadeType.ALL) @JoinColumn private Collection<Child> childCollection; 

You do not need to specify any child link, because the above code will create a column in the child table.

+3
source share

I would let parents save their own children

 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; } } 
+2
source share

As stated in the comments, you should take care of the consistency of the object graph with the child / parent relationship. This consistency will not be free when JSON comes directly from the POST request.

You must annotate the parent and child fields using @JsonBackReference and @JsonManagedReference .

Parent class:

 @OneToMany(mappedBy = "parentId") @JsonBackReference private Collection<Child> childCollection; 

Child class:

 @JoinColumn(name = "parent_id", referencedColumnName = "parent_id") @ManyToOne(optional=false) @JsonManagedReference private Parent parent; 

A similar question with an answer here

Also, if you use @JsonBackReference / @JsonManagedReference in javax.persistence annotated classes combined with Lombok @ToString annotation, you will get a stackoverflow error.

Just exclude the childCollection and parent field from the @ToString annotation with @ToString( exclude = ...)

The same will happen with the Lombok-created equals() method ( @Data , @EqualsAndHashCode ). Just implement these methods manually or use only @Getter and @Setter .

+2
source share

All Articles