Jpa spring数据保存仅在父级不存在时创建级联子级

Jpa spring数据保存仅在父级不存在时创建级联子级,jpa,spring-data,Jpa,Spring Data,我有以下实体:Question有OneToOneConfig。而Config有许多选项。全部配置为级联。全部配置为级联(s.附录) 基于RequestDTO(requestConfig),我为一个新问题或一个现有问题创建了选项实体,其id=null 在这两种情况下,我都希望访问新选项的生成ID。但是,它确实适用于新问题,但不适用于现有问题: 新问题(确定) 实体:问题 @Entity public class Question { @OneToOne(fetch = FetchType.

我有以下实体:
Question
有OneToOne
Config
。而
Config
有许多
选项。全部配置为级联。全部配置为级联(s.附录)

基于
RequestDTO
requestConfig
),我为一个新问题或一个现有问题创建了
选项
实体,其id=null

在这两种情况下,我都希望访问新
选项的生成ID
。但是,它确实适用于新问题,但不适用于现有问题:

新问题(确定)

实体:问题

@Entity
public class Question {
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "config_id", nullable = false)
    private Config config;

    // ...
}
@Entity
public class Option {
    @ManyToOne
    @JoinColumn(name = "config_id", nullable = false)
    private Config config;

    public Option(Long id, Config config) {
        super();
        this.id = id;
        this.config = config;
    }
    // ...
}
实体:配置

@Entity
public class Config {

    @OneToOne(mappedBy = "config")
    @JoinColumn(name = "question_id", nullable = true)
    private Question question;

    @OneToMany(mappedBy = "config", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Option> options = new ArrayList<>();
    // ...
}

当您对一个新的
问题
调用
questionRepo.save()
时,Spring数据会识别您正试图保存一个新实体,并在内部调用
EntityManager.persist()

EntityManager.persist(entity)
使作为参数传递的实体持久化

但是,当您对现有的
问题
调用
questionRepo.save()
时,Spring数据会在内部调用
EntityManager.merge()

EntityManager.merge(entity)
返回该实体的持久副本

问题是在调用
questionRepo.save()
之前调用了
requestConfig.getNewOptions()
。在您描述的第一种情况下,这并不重要,因为原始实例分配给
question
(即使用
question question=new question(…);
创建的实例),以及使用
行添加到
选项的子实例,变得持久化,并获取自动生成的id

但是,在第二种情况下,并不重要,因为使用
行将新的子实例添加到
选项
。forEach(o->config.getOptions().add(o))
不会持久化。相反,只有由
questionRepo.save()
返回的副本引用的子实体instance(该副本反过来返回
EntityManager.merge()
的结果)是持久的

调用
questionRepo.save()
(使用
question.getConfig().getNewOptions()
)后,您只需构造
idMapping
映射即可。这两种情况都可以处理

我检查了数据库,它们被插入了


entityManager只返回当前实体的新id,而不是通过cascade保存的相关实体。保存问题后,请尝试通过问题id再次查找。

谢谢您的尝试!虽然您的解释更清楚地说明了问题所在,但建议的解决方案不起作用:配置的
newOptions
字段是在
save(…)
之前构建的(调用
requestDTO.getConfig(…)
并且它不能在
保存
之后执行,因为保存操作的一部分应该存储新选项。
新选项
字段确实包含ID为空的
选项
对象。
@Entity
public class Question {
    @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "config_id", nullable = false)
    private Config config;

    // ...
}
@Entity
public class Config {

    @OneToOne(mappedBy = "config")
    @JoinColumn(name = "question_id", nullable = true)
    private Question question;

    @OneToMany(mappedBy = "config", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Option> options = new ArrayList<>();
    // ...
}
@Entity
public class Option {
    @ManyToOne
    @JoinColumn(name = "config_id", nullable = false)
    private Config config;

    public Option(Long id, Config config) {
        super();
        this.id = id;
        this.config = config;
    }
    // ...
}