使用带有父 ID 的 @PathVariable 通过 REST 保存子项

Using @PathVariable with Parent ID to Save Child over REST

Spring 引导,我有一个 Rest 控制器,我试图在其中保存一个带有父对象的对象。

@Entity
public class Parent {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JsonManagedReference()
    private List<Child> children;

  // getters / setters
}

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonView(Views.Summary.class)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    @NotNull
    @JsonBackReference()
    private Parent parent;

   // getters / setters
}

由于 @JsonBackReference,Jackson 不会序列化完全包含父对象的子对象。所以在我的测试中做类似下面的事情是行不通的...

Child child = new Child()
child.setParent(parent)

ObjectMapper mapper = new ObjectMapper()
String payload = mapper.writeValueAsString(child);

我最终得到以下 JSON:

{ "id": null }

我真正想要的是

{ "id": null, parent: { "id": 1 } }

所以我决定做的是将父 ID 添加为 @PathVariable 并将其传递到我的服务方法中,然后手动设置它。问题是,由于 Parent 在 Child 中不能为空,并且我正在使用 @Valid 验证 Child 我什至没有进入我的方法的关键,以便我可以处理 Parent ID .

@RequestMapping(value = "/{parentId}/children", method = RequestMethod.POST)
public void save(@PathVariable Long parentId, @Valid @RequestBody Child child, BindingResult bindingResult, HttpServletRequest request, HttpServletResponse response) {
        if (bindingResult.hasErrors()) {
            throw new InvalidRequestException("Invalid Child", bindingResult);
        }

        this.storeService.save(parentId, child);
        response.setHeader("Location", request.getRequestURL().append("/").append(child.getId()).toString());
    }

欢迎提出任何建议。

您的 JPA 模型(如您所写)表明 Parent object 包含 Child object 的列表。此外,使用 cascade = CascadeType.ALL 表示这是应该管理 Child object 的 Parent object,而不是相反。

换句话说,如果你想保存你的数据,你需要:

  • 获取或创建 Parent object(好的)
  • 创建一个Childobject(好的)
  • 设置child的parent(好)
  • 将 child 添加到 parent <-- 你错过了这一部分和下一部分
  • 保存 parent(而不是直接保存 child)

每次需要更新children时,在parent中修改,然后保存parent.

这就是为什么在序列化 child 中具有 parent 的 ID 无关紧要。

此外,我建议您将 orphanRemoval=true 添加到 @OneToMany 注释中,这样 children 不再链接到他们的 parent 应该被删除嗯

更新(澄清): 如果您正在使用级联(如果是级联 ALL,则更多),您不会告诉您的应用程序您想要更新 Child 实例。您要做的是更新 parent 中的 child,然后保存 parent。级联将完成剩下的工作。