Hibernate 尝试在设置 parent 后坚持两次 child
Hibernate tries to persist child twice after setting parent
我有这样的 Hibernate 映射:
Parent:
@OneToMany(mappedBy = "parent")
@Valid
private Set<Assignment> assignments;
Child:
@ManyToOne(cascade = {CascadeType.PERSIST})
@JoinColumn(name = "parent_id")
@Valid
private Parent parent;
我有这样的情况:Parent 已经保存在数据库中,我得到了新的作业列表。我做了这样的事情(使用 Spring Data JPA):
parent.getAssignments().addAll(newAssignments);
parent.getAssignments().forEach(assignment -> assignment.setParent(parent));
parentRepository.save(parent);
我在基本实体中有@PrePersist 注释方法(由两者扩展),验证检查在@PrePersist 中初始化的createdDate 是否不为空。基本实体包含:
@NotNull
@Column(name = "created_date")
protected LocalDateTime createdDate;
@PrePersist
public void prePersist() {
setCreatedDate(LocalDateTime.now());
setModifiedDate(LocalDateTime.now());
validateEntity();
}
private void validateEntity() {
Set<ConstraintViolation<BaseEntity>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(this);
if(!violations.isEmpty()) {
throw new RuntimeException(new ValidationMessageBuilder().build(violations));
}
}
我已经检查了调试器下的 objects,例如赋值是 object @17609,Parent 是 @17608。
调用 save() 方法后引发异常。
java.lang.RuntimeException: may not be null => com.foo.bar.model.domain.Assignment.parent.assignments.createdDate.
at com.foo.bar.model.BaseEntity.validateEntity(BaseEntity.java:70)
at com.foo.bar.model.BaseEntity.prePersist(BaseEntity.java:58)
我已经调试并在 Assignment 实体的 @PrePersist 方法中 Hibernate 为另一个 object 调用它,它是 Assignment@17646,其中包含 Parent@17608 和 parent包含 children 个元素的集合,其中一个元素是 @17609.
为什么 hibernate 会尝试持久化另一个 object?
这些是我对你的问题的观察:
抛出的异常不是来自 Hibernate...
由您的验证方法抛出:validateEntity()
,因为您的
child 作业有 null createDate
.
您正在使用 EntityListeners
设置您的 createdDate
和
modifiedDate
并验证您的 bean 值...但是,看起来
(这是我的猜测)您的验证方法正在迭代
(并验证)在休眠之前很久的 child 赋值
对它们执行 @PrePersist
!
我的解决问题的建议:
- 使用这个配置:
Parent:
@OneToMany(mappedBy = "parent", CascadeType = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private Set<Assignment> assignments;
Child:
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
BaseClass:将您的 prePersist
方法重命名为:
@PrePersist
@PreUpdate
public void prePersistOrUpdate() {
setCreatedDate(LocalDateTime.now());
setModifiedDate(LocalDateTime.now());
validateEntity();
}
检查(并根据需要修改)您的基本验证方法。这个
方法应该只验证实例变量(如
createdDate
) 并避免横向 child objects
稍后为 EntityListener
方法修改:
prePersistOrUpdate()
(注意,我删除了 @Valid
注释
因为我不知道它的用途...可能是它被
你的验证框架)。
修改业务逻辑(其中newAssigments
)被持久化
像这样:
parent.getAssignments().addAll(newAssignments);
parent.getAssignments().forEach(assignment -> assignment.setParent(parent));
parentRepository.merge(parent); // This should cascade and persist the new assigments!
我有这样的 Hibernate 映射:
Parent:
@OneToMany(mappedBy = "parent")
@Valid
private Set<Assignment> assignments;
Child:
@ManyToOne(cascade = {CascadeType.PERSIST})
@JoinColumn(name = "parent_id")
@Valid
private Parent parent;
我有这样的情况:Parent 已经保存在数据库中,我得到了新的作业列表。我做了这样的事情(使用 Spring Data JPA):
parent.getAssignments().addAll(newAssignments);
parent.getAssignments().forEach(assignment -> assignment.setParent(parent));
parentRepository.save(parent);
我在基本实体中有@PrePersist 注释方法(由两者扩展),验证检查在@PrePersist 中初始化的createdDate 是否不为空。基本实体包含:
@NotNull
@Column(name = "created_date")
protected LocalDateTime createdDate;
@PrePersist
public void prePersist() {
setCreatedDate(LocalDateTime.now());
setModifiedDate(LocalDateTime.now());
validateEntity();
}
private void validateEntity() {
Set<ConstraintViolation<BaseEntity>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(this);
if(!violations.isEmpty()) {
throw new RuntimeException(new ValidationMessageBuilder().build(violations));
}
}
我已经检查了调试器下的 objects,例如赋值是 object @17609,Parent 是 @17608。
调用 save() 方法后引发异常。
java.lang.RuntimeException: may not be null => com.foo.bar.model.domain.Assignment.parent.assignments.createdDate.
at com.foo.bar.model.BaseEntity.validateEntity(BaseEntity.java:70)
at com.foo.bar.model.BaseEntity.prePersist(BaseEntity.java:58)
我已经调试并在 Assignment 实体的 @PrePersist 方法中 Hibernate 为另一个 object 调用它,它是 Assignment@17646,其中包含 Parent@17608 和 parent包含 children 个元素的集合,其中一个元素是 @17609.
为什么 hibernate 会尝试持久化另一个 object?
这些是我对你的问题的观察:
抛出的异常不是来自 Hibernate... 由您的验证方法抛出:
validateEntity()
,因为您的 child 作业有null createDate
.您正在使用
EntityListeners
设置您的createdDate
和modifiedDate
并验证您的 bean 值...但是,看起来 (这是我的猜测)您的验证方法正在迭代 (并验证)在休眠之前很久的 child 赋值 对它们执行@PrePersist
!
我的解决问题的建议:
- 使用这个配置:
Parent:
@OneToMany(mappedBy = "parent", CascadeType = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private Set<Assignment> assignments;
Child:
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
BaseClass:将您的 prePersist
方法重命名为:
@PrePersist
@PreUpdate
public void prePersistOrUpdate() {
setCreatedDate(LocalDateTime.now());
setModifiedDate(LocalDateTime.now());
validateEntity();
}
检查(并根据需要修改)您的基本验证方法。这个 方法应该只验证实例变量(如
createdDate
) 并避免横向 child objects 稍后为EntityListener
方法修改:prePersistOrUpdate()
(注意,我删除了@Valid
注释 因为我不知道它的用途...可能是它被 你的验证框架)。修改业务逻辑(其中
newAssigments
)被持久化 像这样:parent.getAssignments().addAll(newAssignments);
parent.getAssignments().forEach(assignment -> assignment.setParent(parent));
parentRepository.merge(parent); // This should cascade and persist the new assigments!