gpt4 book ai didi

jpa - 如果父级不存在,则 spring 数据保存仅创建级联子级

转载 作者:行者123 更新时间:2023-12-03 02:16:40 25 4
gpt4 key购买 nike

我有以下实体:问题有OneToOne 配置。而Config有很多Option。全部配置为CASCADE.ALL(见附录)

基于 RequestDTO (requestConfig),我使用 id=null 创建新的 Option 实体,用于新问题或现有问题。

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

新问题(确定)

// RequestDTO requestConfig is a controller parameter
Question question = new Question(...);
Config config = requestDTO.createConfig(Optional.empty());
question.setConfig(config);

LinkedHashMap<String, Option> idMapping = requestConfig.getNewOptions();

idMapping.forEach((foo, option) -> System.out.println(option.getId())); // all null

question = questionRepo.save(question);

idMapping.forEach((foo, option) -> System.out.println(option.getId())); // 675, 676, ... etc

现有问题(已损坏,请参阅最后一行,id 为空)

// RequestDTO requestConfig is a controller parameter
Question question = questionRepo.find(...);
Config config = requestDTO.getConfig(Optional.of(question.getConfig()));
question.setConfig(config);

LinkedHashMap<String, Option> idMapping = requestConfig.getNewOptions();

idMapping.forEach((foo, option) -> System.out.println(option.getId())); // all null

question = questionRepo.save(question);

idMapping.forEach((foo, option) -> System.out.println(option.getId())); // all null

为什么会发生这种情况?我希望 LinkedHashMap idMapping 包含新创建的 Option 及其创建的 id,因为它们是从问题保存操作级联的。我检查了数据库,它们已插入!

<小时/>

附录

作为引用,这是我的 RequestDTO 和实体:

public class RequestDTO {
private LinkedHashMap<String, OptionDTO> optionDTOs;
@JsonIgnore
private LinkedHashMap<String, Option> newOptions = new LinkedHashMap<>();

public Config getConfig(Optional<Config> oldConfig) {
Config config = new Config();
if (oldConfig.isPresent()) {
config = oldConfig.get();
}
// update the options based on our OptionDTOs
config.getOptions().clear();
optionDTOs.stream()
.map(o -> {
try { // to find the existing option
Option theOption = config.getOptions().stream()
// try to find in given config
.filter(existing -> o.getId().equals(existing.getId()))
.findAny()
// fallback to db
.orElse(optionRepo.findOne(Long.parseLong(o.getId())));
if (null != theOption) {
return theOption;
}
} catch (Exception e) {
}
// handle as new one by creating a new one with id=null
Option newOption = new Option(null, config);
newOptions.add(newOption);
return newOption;
})
.forEach(o -> config.getOptions().add(o));
return config;
}
// getters
}

实体:问题

@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;
}
// ...
}

最佳答案

当您调用questionRepo.save()时上新Question ,Spring Data 识别出您正在尝试保存新实体,并调用 EntityManager.persist()内部。

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

但是,当您调用questionRepo.save()时在现有的Question上,Spring Data 调用 EntityManager.merge()内部。

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

问题是你调用requestConfig.getNewOptions() 调用 questionRepo.save() 之前。在您描述的第一种情况下这并不重要,因为原始实例分配给 question (即使用 Question question = new Question(...); 创建的实例),以及添加到 Option 的子实例使用线 .forEach(o -> config.getOptions().add(o))成为持久化,并获取自动生成的id。

但是,在第二种情况下,它确实很重要,因为新的子实例添加到 Option使用线 .forEach(o -> config.getOptions().add(o))不要变得执着。相反,只有 questionRepo.save() 返回的副本引用子实体实例。 (又返回 EntityManager.merge() 的结果)是持久的。

您应该简单地构造 idMapping调用 questionRepo.save()绘制 map (使用 question.getConfig().getNewOptions() )。这应该可以处理这两种情况。

关于jpa - 如果父级不存在,则 spring 数据保存仅创建级联子级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50634305/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com