2017-05-11 84 views
1

我有這樣的Hibernate映射後兩次堅持孩子:Hibernate試圖設置父

家長:

@OneToMany(mappedBy = "parent") 
@Valid 
private Set<Assignment> assignments; 

兒童:

@ManyToOne(cascade = {CascadeType.PERSIST}) 
@JoinColumn(name = "parent_id") 
@Valid 
private Parent parent; 

我有這樣的情況:家長已經存在於數據庫中,我得到新的Assignments列表。我做(使用Spring數據JPA)這樣的事:

parent.getAssignments().addAll(newAssignments); 
parent.getAssignments().forEach(assignment -> assignment.setParent(parent)); 
parentRepository.save(parent); 

我得在基礎機構(由兩個擴展)@PrePersist註解的方法,與檢查驗證,如果createdDate,這是在@PrePersist初始化不空值。基礎機構包括:

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

我檢查下調試的對象,例如分配是對象@ 17609和家長是@ 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) 

我已經調試和分配實體的@PrePersist方法休眠調用它的另一個對象,這是分配@ 17646,其中包含父@ 17608,和家長包含的子集的一個元素,它是@ 17609。

爲什麼hibernate試圖堅持另一個對象?

+0

我認爲你應該只添加assignements母公司和堅持父母,沒有需要設置家長分配 – Antoniossss

+0

你得到了什麼樣的例外...你可以發佈它嗎? –

+0

@Antoniossss,如果我沒有設置父級,hibernate不會自動執行此操作,並嘗試使用parentId = null持續賦值,這是不正確的。如果我在Assignment的父映射中更改了實體關係並添加了nullable =「false」,那麼hibernate會嘗試執行相同的操作(將parent設置爲賦值),併發生相同的異常。 – mdziob

回答

1

這些都是我的觀察問題的方法:

  1. 被拋出的異常是不是從休眠......它被 通過您的驗證方法拋出:validateEntity(),因爲你的孩子 有assigments一個null createDate

  2. 您使用EntityListeners用於設置createdDatemodifiedDate和驗證你的bean值...但是,似乎 (這是我的猜測),您的驗證方法是迭代 (和驗證)在兒童assigments很久之前休眠 對他們執行@PrePersist

我的建議來解決這個問題:

  1. 使用此配置:

家長:

@OneToMany(mappedBy = "parent", CascadeType = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}) 
private Set<Assignment> assignments; 

兒童:

@ManyToOne 
@JoinColumn(name = "parent_id") 
private Parent parent; 

BaseClass的:重命名prePersist方法爲:

@PrePersist 
@PreUpdate 
public void prePersistOrUpdate() { 
    setCreatedDate(LocalDateTime.now()); 
    setModifiedDate(LocalDateTime.now()); 
    validateEntity(); 
} 
  • 檢查(和如果需要的話修改)你的基地驗證方法。這 方法只能驗證實例變量(如 createdDate),避免橫向子對象,這將是 後來爲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!

  • +0

    你說得對 - 問題全在驗證中。經過一些改動後,一切正常! – mdziob