我希望将父实体与20个子实体持久化, 我的代码在下面
父类
@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个for循环? 这可行吗?有没有其他方法或配置,我可以自动坚持父母和孩子?
答案 0 :(得分:8)
修复您的Parent类:
@OneToMany(mappedBy = "parent")
mappedBy 属性应指向关系另一侧的字段。正如JavaDoc所说:
拥有这种关系的领域。除非关系是单向的,否则是必需的。
此外,您应该在周期中明确地保留Child实体:
for(Child tha : parent.getChildCollection()) {
...
getEntityManager().persist(tha);
...
}
在评论中注意到Alan Hay,您可以使用级联设施,让EntityManager自动保留所有子实体:
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
您可以在Vlad Mihalcea's blog中找到有关级联(和JPA本身)的更多详细信息。
答案 1 :(得分:7)
通常,@ JoinColumn表示该实体是关系的所有者&amp; mappedBy表示实体是关系的反转。
所以,如果你想跟随
@OneToMany(mappedBy = "parent")
private Collection<Child> childCollection;
这意味着它是关系的反转,并且它不会设置对其子项的父引用。
要设置对其子级的父级引用,您必须按以下方式创建上述实体关系的所有者。
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn
private Collection<Child> childCollection;
您不需要设置任何子引用,因为上面的代码将在子表中创建一个列。
答案 2 :(得分:3)
正如评论中指出的那样,您必须注意与子/父关系的对象图一致性。当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
此外,如果您在@JsonBackReference
带注释的类中使用@JsonManagedReference
/ javax.persistence
并结合Lombok的@ToString
注释,则会出现stackoverflow错误。
只需使用childCollection
parent
注释中排除@ToString
和@ToString( exclude = ...)
字段
Lombok生成的equals()
方法(@Data
,@EqualsAndHashCode
)也会发生同样的情况。只需手动实现这些方法或仅使用@Getter
和@Setter
注释。
答案 3 :(得分: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;
}
}
答案 4 :(得分:0)
我正在使用lombok在我的实体类上生成getter和setter属性。
当我尝试保存有孩子的父实体时,我也面临子实体NULL引用ID的问题。
当我添加子代时,在我的父代实体上,然后在子代上设置父代的“ this”引用。
在我的示例中,我有一个用户表和一个地址表,其中一个用户可以有很多地址。
我创建了如下的域类。
例如address.setUser(this);
package com.payment.dfr.entities;
import lombok.Data;
import javax.persistence.*;
import java.math.BigInteger;
@Entity
@Data
@Table(name="User")
public class User {
@Id
@GeneratedValue
private BigInteger RecordId;
private String Name;
private String Email;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Address> addresses = new ArrayList<>();
public void addAddress(Address address){
address.setUser(this);
addresses.add(address);
}
}
@Entity
@Data
@Table(name="UserAddress")
public class Address {
@Id
@GeneratedValue
private BigInteger RecordId;
private String AddressLine;
private String City;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="UserId")
private User user;
}
This is how I save user with address
User newUser = new User();
newUser.setName("Papa");
newUser.setEmail("manish@gmail.com");
Address address1 = new Address();
address1.setAddressLine("4401 Central Ave");
address1.setCity("Fremont");
newUser.addAddress(address1);
Address address2 = new Address();
address2.setAddressLine("4402 Central Ave");
address2.setCity("Fremont");
newUser.addAddress(address2);
User user1 = userRepository.save(newUser);
log.info(user1.getRecordId().toString());