在 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
。虽然只有 customerOrder
和 invoice
两个对象相互引用,但是在序列化时递归下降。
解决方案:
使用@JsonIgnore
:
在 Invoice
实体的 cusotmerOrder
属性 上放置一个 @JsonIgnore
,这将防止在 Invoice
实体内序列化 customerOrder
。
- 优点:开销较少
- 缺点:无法动态控制何时序列化到哪个级别。
使用 @JsonIgnore
或使用一对 @JsonBackReference
& @JsonManagedReference
具有相似的缺点。
其他:
要在不同的响应(针对不同的路由)中动态控制响应的深度,您可以选择 @JsonView
或 @JsonFilter
。
使用示例:
我有两个一对一相关的模型。我无视其中一个在役模型的保存方法 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
。虽然只有 customerOrder
和 invoice
两个对象相互引用,但是在序列化时递归下降。
解决方案:
使用@JsonIgnore
:
在 Invoice
实体的 cusotmerOrder
属性 上放置一个 @JsonIgnore
,这将防止在 Invoice
实体内序列化 customerOrder
。
- 优点:开销较少
- 缺点:无法动态控制何时序列化到哪个级别。
使用 @JsonIgnore
或使用一对 @JsonBackReference
& @JsonManagedReference
具有相似的缺点。
其他:
要在不同的响应(针对不同的路由)中动态控制响应的深度,您可以选择 @JsonView
或 @JsonFilter
。
使用示例: