在 rest post 方法中附加了相同的值

The same value gets appended in rest post method

我有两个一对一相关的模型。我无视其中一个在役模型的保存方法 class。但是当我通过 rest API 保存它们时,它会连续追加同一个对象。

我有 2 个具有一对一关系的模型 Invoice 和 CustomerOrder。

发票模型

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

    @Column(nullable = true)
    private LocalDate date;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "customerOrder")
    private Invoice invoice;

    public Invoice getInvoice() {
        return invoice;
    }

    public void setInvoice(Invoice invoice) {
        this.invoice = invoice;
    }

    ....

和发票

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

    @Column(precision = 8, scale = 2)
    private BigDecimal amount;

    private LocalDate issued;

    private LocalDate due;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "order_id")
    private CustomerOrder customerOrder;

    public CustomerOrder getCustomerOrder() {
        return customerOrder;
    }

    public void setCustomerOrder(CustomerOrder customerOrder) {
        this.customerOrder = customerOrder;
    }
...

还有我的服务保存方法


    public void saveInvoice(Invoice invoice, Long order_id) {
        CustomerOrder customerOrder = customerOrderRepository.getById(order_id);
        invoice.setCustomerOrder(customerOrder);
        invoiceRepository.save(invoice);
    }

控制器方法

@PostMapping(path = "{order_id}")
    public void saveInvoice(@RequestBody Invoice invoice,@PathVariable(value = "order_id") Long order_id) {
        invoiceService.saveInvoice(invoice, order_id);
    }

但是当保存同一个对象时是连续追加的。

        "id": 3,
        "amount": 10.20,
        "issued": "2020-09-20",
        "due": "2020-09-21",
        "customerOrder": {
            "id": 2,
            "date": "2020-09-20",
            "invoice": {
                "id": 3,
                "amount": 10.20,
                "issued": "2020-09-20",
                "due": "2020-09-21",
                "customerOrder": {
                    "id": 2,
                    "date": "2020-09-20",
                    "invoice": {
                        "id": 3,
                        "amount": 10.20,
                        "issued": "2020-09-20",
                        "due": "2020-09-21",
                        "customerOrder": {
                            "id": 2,
                            "date": "2020-09-20",
                            "invoice": { ....

不断。

@OneToOne 不是关系的最佳选择,f.e。它限制了实体的延迟加载。你也有来自关系双方的 CascadeType.ALL 这可能会导致一些问题。更改与@OneToMany one CustomerOrder 和 many Invoice 的关系并删除级联。先保存 CustomerOrder,再保存 Invoice。但是如果你想使用@OneToOne,请查看注解@MapsId https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

在 REST api 中直接使用实体作为 RequestBody 不是好的做法。尝试使用 InvoiceRequest class 作为输入并使用 InvoiceDTO 作为输出以将视图与业务逻辑分开。这也将解决 Jackson serialization/deserialization 问题。

这里实际发生了什么:

  • CustomerOrder 实体有一个名为 invoice 的 属性 个 Invoice
  • Invoice 实体有 属性 个 CustomerOrder 名为 customerOrder

当 jackson 序列化器尝试序列化这个 CustomerOrder 时,它发现它有一个 invoice 属性,里面也有 customerOrder。虽然只有 customerOrderinvoice 两个对象相互引用,但是在序列化时递归下降。

解决方案:

使用@JsonIgnore:

Invoice 实体的 cusotmerOrder 属性 上放置一个 @JsonIgnore,这将防止在 Invoice 实体内序列化 customerOrder

  • 优点:开销较少
  • 缺点:无法动态控制何时序列化到哪个级别。

使用 @JsonIgnore 或使用一对 @JsonBackReference & @JsonManagedReference 具有相似的缺点。

其他:

要在不同的响应(针对不同的路由)中动态控制响应的深度,您可以选择 @JsonView@JsonFilter

使用示例: