2016-02-04 95 views
6

我要坚持父实体20个子实体, 我的代码如下JPA坚持家长和孩子有一对多的关系

父类

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

子类

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

所以如果有20个子表,那么我必须在它们的每一个中设置父引用,以便我必须为循环写入20个引用? 可行吗?有没有其他方式或配置可以自动坚持父母和孩子?

+0

这似乎是一个比JPA问题更多的JSON问题。如果你的JSON被解组,那么设置适当的关系,然后让孩子在保存父对象时保持不变,只需将相关的级联选项添加到@OneToMany(假设你的映射是正确的) –

+2

如果你没有发送孩子 - >父亲关系回来,或者它没有设置从JSON构建的内容,那么是的,你需要在每个子实体中手动设置它。另一种方法是单向关系:从OneToMany中移除mappedby =“parent”,而是指定一个JoinColumn。这将导致OneToMany在子表中设置外键,而不是通过子对其父项的引用来设置(然后您应该删除子项的父属性和映射) – Chris

回答

5

解决您的父类:

@OneToMany(mappedBy = "parent") 

的mappedBy属性应指向上关系的其他侧方视野。由于JavaDoc说:

拥有该关系的字段。除非关系是单向的,否则是必需的。

你也应该明确地坚持儿童实体周期:

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

由于Alan Hay在评论注意到,您可以使用级联设施,让EntityManager的自动坚持所有儿童实体:

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

有关级联(和JPA本身)的更多详细信息,请参阅Vlad Mihalcea's blog

+0

这不会需要级联选项@OneToMany ? –

+0

但20个不同的孩子集合,我将不得不写20个不同的循环? – Gora

+0

@Bharath Reddy,我想是的,cos 20个不同的子集合是20个不同的父对象,你将调用20次方法保存(...)。 –

2

我先给家长坚持它自己的孩子

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

正如你必须要注意父/子关系的对象图一致性的评论中指出。当JSON直接来自POST请求时,这种一致性不会免费。

您必须用@JsonBackReference@JsonManagedReference注释父级和子级字段。

父类:

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

子类:

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

与回答类似的问题是here

此外,如果结合使用上javax.persistence注释类@JsonBackReference/@JsonManagedReference与龙目岛@ToString注释你会在stackoverflow erro招致河

只排除childCollection@ToString批注与@ToString(exclude = ...)

parent领域同样将与龙目岛的发生产生equals()方法(@Data@EqualsAndHashCode)。只需手动实施这些方法或仅使用@Getter@Setter注释。

3

通常,@JoinColumn指示该实体是关系的所有者 &的mappedBy指示该实体的关系是的逆。

所以,如果你试图像下面

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

这意味着它是关系相反,它不会将父参考其子。

要设置其子对象的父引用,必须按以下方式使上述实体关系的所有者。

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

您不需要设置任何子引用,因为上面的代码将在子表中创建一列。

+0

这不是一个更好的方法,因为它叫做“Unidirectional @ OneToMany”,然后Hibernate将创建两次多个SQL请求到数据库https://vladmihalcea.com/2017/3月29日/的最佳路到MAP-A-一对多关联与 - JPA-和休眠/ – panser