JPA Persist parent and child with one to many relationship

拜拜、爱过 提交于 2019-12-31 12:21:10

问题


I want to persist parent entity with 20 child entities, my code is below

Parent Class

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

Child 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 parent reference in each of them for that I have to write 20 for loops? Is it feasible? is there any other way or configuration where I can automatically persist parent and child?


回答1:


Fix your Parent class:

@OneToMany(mappedBy = "parent")

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

The field that owns the relationship. Required unless the relationship is unidirectional.

Also you should explicitely persist Child entity in cycle:

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

As Alan Hay noticed in comment, you can use cascade facilities and let EntityManager automatically persist all your Child entities:

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

More details about cascades (and JPA itself) you can find in Vlad Mihalcea's blog.




回答2:


Generally, @JoinColumn indicates that the entity is the owner of the relationship & mappedBy indicates that the entity is the inverse of the relationship.

So, if you are trying like following

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

That means it is inverse of the relationship and it will not set parent reference to its child.

To set parent reference to its child, you have to make the above entity owner of the relationship in the following way.

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

You need not set any child reference because above code will create a column in the child table.




回答3:


As pointed out in the comments you must take care of the object graph consistency with child/parent relationship. This consistency won't come free when JSON is coming directly from i.e. a POST request.

You have to annotate the parent and child field with @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;

Similar question with answer is here

Furthermore, if you use @JsonBackReference/@JsonManagedReference on javax.persistence annotated classes in combination with Lombok's @ToString annotation you will incur in stackoverflow error.

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

The same will happen with Lombok's generated equals() method (@Data, @EqualsAndHashCode). Just implements those methods by hand or to use @Getter and @Setter annotations only.




回答4:


I would let the parent persist it's 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;
    }

}


来源:https://stackoverflow.com/questions/35197947/jpa-persist-parent-and-child-with-one-to-many-relationship

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!