У меня есть следующие объекты: Question
имеет OneToOne Config
.И Config
имеет много Option
с.Все настроены на CASCADE.ALL
(с. Приложение)
На основе RequestDTO
(requestConfig
) я создаю новые Option
сущности с id=null
для НОВОГО вопроса или СУЩЕСТВУЮЩЕГО вопроса.
В обоих случаях Я хочу получить доступ к сгенерированным идентификаторам нового Options
. .Однако он работает для новых вопросов, но не для существующих:
Новый вопрос (ОК)
// 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
Существующий вопрос (Сломаны, см. Последнюю строку, идентификаторы равны нулю)
// 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
с их созданными идентификаторами, так как они были каскадированы из операции сохранения вопроса.Я проверил БД, и они вставлены!
ПРИЛОЖЕНИЕ
Для справки, вот мои 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;
}
// ...
}