java - Spring boot JPA - 双向关系:返回外键而不是相关对象
问题描述
我有两个实体:Customer和Address。
这是一种双向关系——一个地址可以有多个客户(oneToMany),一个客户只能有一个地址(manyToOne)。
为客户返回执行 GET 请求:
[
{
"id": 1,
"name": "Foo",
"contact": "5512312",
"email": "Foo@gmail.com",
"address": {
"id": 1,
"street": "X",
"postalCode": 123,
"houseNo": "10",
"city": "New York"
}
}
]
当使用 POST 请求添加与 DB 中存在的地址属性完全相同的新客户时,json 响应返回与 DB 中现有对象相关的外键,而不是对象本身:
[
{
"id": 1,
"name": "Foo",
"contact": "5512312",
"email": "Foo@gmail.com",
"address": {
"id": 1,
"street": "X",
"postalCode": 123,
"houseNo": "10",
"city": "New York"
}
},
{
"id": 2,
"name": "Bar",
"contact": "5512312",
"email": "Bar@gmail.com",
"address": 1 <----------- it returns the foreign key instead of the object
}
]
所以我期望的是,每当添加一个新客户,其地址已经存在于数据库中,它应该返回地址对象,而不是来自 json 响应的外键。
代码:
客户.java
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
@Entity
@Table
public class Customer {
@Id
@SequenceGenerator(
name = "customer_sequence",
sequenceName = "customer_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "customer_sequence"
)
private Long id;
private String name;
private String contact;
private String email;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", nullable = false)
private Address address;
[...]
地址.java
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
@Entity
@Table
public class Address {
@Id
@SequenceGenerator(
name = "address_sequence",
sequenceName = "address_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "address_sequence"
)
private Long id;
private String street;
private int postalCode;
private String houseNo;
private String city;
@JsonIgnore
@OneToMany(mappedBy = "address")
private Set<Customer> customers;
[...]
客户控制器.java
//...
@PostMapping
public void createCustomer(@RequestBody Customer customer) {
customerService.createCustomer(customer);
}
[...]
以及将客户保存到数据库的服务,它还确保如果数据库中已经存在地址,则不会创建任何地址(它检查参数中的每个属性是否相等):
//...
public void createCustomer(Customer customer) {
Optional<Customer> customerWithExistingAddress = customerRepository.findAll()
.stream()
.filter(x -> x.getAddress().equals(customer.getAddress()))
.findFirst();
customerWithExistingAddress.ifPresent(c -> customer.setAddress(c.getAddress()));
customerRepository.save(customer);
}
[...]
解决方案
由于 JsonIdentityInfo,您可能会遇到这种行为,所以这是一个序列化问题,您没有持久性问题。我假设您使用的是关系数据库(NoSql 的 Hibernate 具有类似 Jpa 的注释,但这会使这成为一个不同的问题)并且数据被正确保存。
请参阅javadocs:
在实践中,这是通过将第一个实例序列化为完整的对象和对象标识,以及对对象的其他引用作为参考值来完成的
推荐阅读
- woocommerce - Woocommerce Hook 上的语法错误(T_ENCAPSED_AND_WHITESPACE)
- delphi - 我在使用 urldecode 方法时遇到错误
- javascript - JavaScript替换数组值和移位增量数
- actions-on-google - 在 Google Assistant App 中拨打电话的问题
- maven - 为 Maven pom 提供外部参数并在 application.properties 文件中替换相同的参数
- java - 在数组中打印用户输入显示为空
- php - mysql php的左连接查询
- java - 如何克服此错误“com.mongodb.diagnostics.logging.JULLogger log”
- c# - 在 C# 中查找 Json 数组中的特定项目
- .net-core - Web API 将 JSON 对象转换为简单的参数