- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下实体:问题
有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/
我是一名优秀的程序员,十分优秀!