java Sping Boot JPA -双向关系:返回外键而不是相关对象

vnzz0bqm  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(173)

我有两个实体:客户地址
这是一种***双向关系***-一个地址可以有多个客户(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
    }
]

因此,我期望的是,每当添加一个新客户时,如果该客户的地址 * 已经存在于数据库中 *,那么它应该返回 *address对象 *,而不是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;
    [...]

CustomerController.java

//...
@PostMapping
    public void createCustomer(@RequestBody Customer customer) {
        customerService.createCustomer(customer);
    }

[...]

而***service***将客户保存到DB中,这也确保如果数据库中已经存在地址,则不会创建地址(它检查每个属性是否与参数相等):

//...
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);
    }

[...]
hkmswyz6

hkmswyz61#

你可能会因为JsonIdentityInfo而得到这种行为,所以这是一个序列化问题,而不是持久化问题。我假设你使用的是关系数据库(Hibernate for NoSql有类似Jpa的注解,但这会使这成为一个不同的问题),并且数据被正确持久化。
参见the javadocs
在实践中,这是通过将第一个示例序列化为完整对象和对象标识,并将对该对象的其他引用序列化为引用值来实现的

q5iwbnjs

q5iwbnjs2#

删除@JsonIdentityInfo

相关问题