JPA CASCADE PERSIST和Spring CrudRepository

时间:2019-02-19 06:57:08

标签: spring hibernate jpa

(注意:已编辑以添加代码以重现行为)

我有以下三个实体

@Entity
public class ClassA {
  @Id private UUID id = UUIDGenerator.generate();
  @OneToMany(mappedBy = "classA", cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.REMOVE}, orphanRemoval = true)
  List<ClassB> classBs= new ArrayList<>();
 //setters and getters
 }

@Entity
public class ClassB {
  @Id private UUID id = UUIDGenerator.generate();

  @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REMOVE},
        orphanRemoval = true, mappedBy = "classB")
  private ClassC classC;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "classA_id")
  private ClassA classA;
  // setters and getters

@Entity
public class ClassC {
  @Id private UUID id = UUIDGenerator.generate();
  @OneToOne //(fetch = FetchType.LAZY)
  @MapsId
  private ClassB classB;
  //setters and getters
}

public interface ClassARepository extends CrudRepository<ClassA, UUID> {}

//Example code to reproduce
ClassC classC_1 = new ClassC();
ClassC classC_2 = new ClassC();
ClassB classB_1 = new ClassB();
ClassB classB_2 = new ClassB();
classC_1.setClassB(classB_1);
classC_2.setClassB(classB_2);
classB_1.setClassC(classC_1);
classB_2.setClassC(classC_2);
ClassA classA = new ClassA();
classB_1.setClassA(classA);
classB_2.setClassA(classA);

classA.getClassBs().add(classB_1);
classA.getClassBs().add(classB_2);

classARepository.save(classA); 

我正在使用Spring Boot和CRUD存储库。第一次尝试保存类型A的实体时,我希望由于有了CascadeType.PERSIST批注,将保存类A,B和C的所有层次结构。但是事实并非如此,我回来了 org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find classB with id ...

如果我将@OneToMany级联类型更改为CascadeType.ALL,则将保存classA和classB,但不保存classC。如果我将所有层叠类型更改为ALL,则将保存所有内容。

但是,我只想在创建新实体时而不是在合并时级联保存操作,我认为这正是PERSIST的意思。有人可以解释上述行为,我如何实现自己想要的?

致谢

1 个答案:

答案 0 :(得分:0)

我正在回答自己的问题:

似乎问题出在id生成策略上。在这种情况下,我在存储在存储库中之前会生成ID,这会引起麻烦。具体地

据我所见SimpleJpaRepository拥有此代码

public <S extends T> S save(S entity) {
    if (this.entityInformation.isNew(entity)) {
        this.em.persist(entity);
        return entity;
    } else {
        return this.em.merge(entity);
    }
}

此处是JpaPersistableEntityInformation实体是否为新实体的决定

public boolean isNew(T entity) {
    return entity.isNew();
}

entity.isNew()的定义如下:

@Transient
public boolean isNew() {
    return null == this.getId();
}

因此,换句话说,id生成策略实际上会影响级联的结果。实际上,我通过将id都更改为

来验证了我的假设
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

瞧,一切正常。

这不是理想的情况,但至少我知道为什么会这样。那么,PERSIST基本上仅适用于数据库生成的ID?似乎很奇怪,所以如果有人对如何解决此问题有任何建议,请告诉我们。

致谢