Spring 如何将前端提供的临时ID映射到生成的后端ID?
用例:用户可以使用JavaScript编写的单页web应用程序来CRUD多项选择题Spring 如何将前端提供的临时ID映射到生成的后端ID?,spring,spring-boot,jpa,spring-data,spring-data-jpa,Spring,Spring Boot,Jpa,Spring Data,Spring Data Jpa,用例:用户可以使用JavaScript编写的单页web应用程序来CRUD多项选择题 创建新问题和添加一些选项都发生在浏览器/前端(FE)中 FE为问题和所有选项创建并使用临时ID(“_1”、“_2”、…),直到用户单击保存按钮 保存新创建的问题时,FE将包含临时ID的JSON发送到后端 因此,FE希望创建一个包含映射临时id->后端id的201来更新其id 用户决定添加另一个选项(FE端再次使用临时id) 用户单击save,FE发送更新的问题,其中包含后端id(针对问题和现有选项)和临时id(针
201来更新其id
@实体
公开课问题{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
@OneToMany(mappedBy=“config”,fetch=FetchType.EAGER,cascade=CascadeType.ALL,orphan=true)
私有列表选项=新建ArrayList();
// ...
}
@实体
公共类选项{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
@许多酮
@JoinColumn(name=“question\u id”,null=false)
私人问题;
公共选项(长id,配置){
this.id=id;
这个问题=问题;
}
// ...
}
控制器
@RestController
@请求映射(“/问题”)
公共类AdminQuestionsController{
@自动连线
私人问题库问题库;
@自动连线
私人期权库期权回购;
@PutMapping(“/{id}”)
@ResponseStatus(HttpStatus.OK)
公共问题到updateQuestion(@PathVariable(“id”)字符串id,@RequestBody问题到requestDTO){
Question-Question=questionRepo.findOneById(Long.parseLong(id));
//将保留临时id到新创建的选项的映射。
Map newOptions=newhashmap();
//更新选项
question.getOptions().clear();
requestDTO.getOptions().stream()
.map(o->{
尝试{//查找现有选项
Option theOption=question.getOptions().stream()
//尝试在给定配置中查找
.filter(现有->o.getId().equals(现有.getId()))
.findAny()
//回退到数据库
.orElse(optionRepo.findOne(Long.parseLong(o.getId())));
如果(null!=选项){
返回选项;
}
}捕获(例外e){
}
//通过创建id=null的新句柄,将其作为新句柄处理
选项newOption=新选项(空,配置);
newOptions.put(o.getId(),newOption);
返回新选项;
})
.forEach(o->question.getOptions().add(o));
问题=问题报告保存(问题);
//创建id映射
Map idMap=newhashmap();
对于(条目e:newOptions.entrySet()){
put(e.getKey(),e.getValue().getId());
//问题:e.getValue().getId()为空
}
返回QuestionDToResult=QuestionDToFrom(问题,idMap);
}
}
在控制器中,我标记了问题:e.getValue().getId()为空
这样的控制器应该如何创建idMap?您可以在
问题
和选项
类中创建附加字段,并标记为@Transient
,以确保它不会持久化
class Question {
....
private String id; // actual data field
@Transient
private String tempId;
// getter & setter
}
最初,当UI发送数据时,设置tmpId
并持久化对象。成功操作时,id
将具有实际id值。现在,让我们创建映射(tmpId->implementd)
关于控制器代码,在添加新选项之前,您正在清除所有现有选项。如果您得到的问题对象的id(实际)字段已经填充,您可以直接将其持久化。这不会影响任何事情。另外,如果它在这方面有一些变化,它将被持久化
class Question {
....
private String id; // actual data field
@Transient
private String tempId;
// getter & setter
}
关于您的控制器代码,您正在清除
question.getOptions().clear();
在此之后,您可以简单地添加新选项
question.setOptions(requestDTO.getOptions());
question = questionRepo.save(question);
我希望现在能有所帮助。最好是单独保存每个选项,然后在地图上保存生成的Id 我做了下面的测试,效果非常好
@Autowired
void printServiceInstance(QuestionRepository questions, OptionRepository options) {
Question question = new Question();
questions.save(question);
question.add(new Option(-1L, question));
question.add(new Option(-2L, question));
question.add(new Option(-3L, question));
question.add(new Option(-4L, question));
Map<Long, Long> idMap = new HashMap<>();
question.getOptions().stream()
.filter(option -> option.getId() < 0)
.forEach(option -> idMap.put(option.getId(), options.save(option).getId()));
System.out.println(idMap);
}
更新示例:
@Autowired
void printServiceInstance(QuestionRepository questions, OptionRepository options) {
Question question = new Question();
Question merged = questions.save(question);
merged.add(new Option(-1L, 1, merged));
merged.add(new Option(-2L, 2, merged));
merged.add(new Option(-3L, 3, merged));
merged.add(new Option(-4L, 4, merged));
questions.save(merged);
System.out.println(questions.findById(merged.getId()).get().getOptions());//
}
控制台输出:[选项[id=2,订单=1],选项[id=3,订单=2],选项[id=4,订单=3],选项[id=5,订单=4]]
注意:不需要映射来控制新ID,前端应该通过按选项的顺序获取它来知道。因此,您需要区分FE生成的ID和待生成的ID? 你可以
在任何情况下,当混合两个ID生成器时,请注意冲突。您能否描述一下选项构造函数,您在其中提供了param Config,但没有使用它,而是使用了问号,另一点是,当您尝试处理新选项,然后再次使用带有空ID的Config时,您能否定义
question.setOptions(requestDTO.getOptions());
question = questionRepo.save(question);
@Autowired
void printServiceInstance(QuestionRepository questions, OptionRepository options) {
Question question = new Question();
questions.save(question);
question.add(new Option(-1L, question));
question.add(new Option(-2L, question));
question.add(new Option(-3L, question));
question.add(new Option(-4L, question));
Map<Long, Long> idMap = new HashMap<>();
question.getOptions().stream()
.filter(option -> option.getId() < 0)
.forEach(option -> idMap.put(option.getId(), options.save(option).getId()));
System.out.println(idMap);
}
@Column(name = "order_num")
private Integer order;
public Option(Long id, Integer order, Question question) {
this.id = id;
this.question = question;
this.order = order;
}
@Autowired
void printServiceInstance(QuestionRepository questions, OptionRepository options) {
Question question = new Question();
Question merged = questions.save(question);
merged.add(new Option(-1L, 1, merged));
merged.add(new Option(-2L, 2, merged));
merged.add(new Option(-3L, 3, merged));
merged.add(new Option(-4L, 4, merged));
questions.save(merged);
System.out.println(questions.findById(merged.getId()).get().getOptions());//
}