2016-02-04 98 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