单向外键列在保存时不会更新

问题描述 投票:0回答:1

我在更新现有实体的单向外键字段时遇到问题。客户端发送包含完整实体数据(包括父实体和子实体)的 PUT 请求,但在保存时仅更新原始值,而不会更新关联实体的引用。
我想知道是否缺少注释或配置,或者我需要自己实现该功能,如果是,如何实现。我这么问是因为现有代码表明这应该可以开箱即用。

作为参考,我有一个较旧的代码库,最近从

升级
  • Spring Boot:2.1.3 至 3.3.1
  • 休眠:5.4.1 至 6.5.2.最终版

我有以下简化的实体:

@Data
@Entity
@Audited
@EqualsAndHashCode(callSuper = true)
@Table(name = "PERSON")
// The listener listens for PrePersist and PreUpdate, but does not touch the problematic fields.
@EntityListeners(PersonListener.class)
public class Person {
    @Id
    @Column(name = "id", nullable = false, insertable = false, updatable = false)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @ManyToOne(targetEntity = Country.class, fetch = FetchType.LAZY)
    @JoinColumn(name = "birth_country_id", referencedColumnName = "id", foreignKey = @ForeignKey(name = "fk_birth_country"))
    @RestResource(exported = false)
    private Country birthCountry;

    @ManyToMany(targetEntity = Address.class, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY)
    @JoinTable(name = "person_address",
            joinColumns = @JoinColumn(name = "person_id"),
            inverseJoinColumns = @JoinColumn(name = "address_id")
    )
    private List<Address> addresses = new ArrayList<>();
    // Other fields omitted for brevity.
}

birthCountry
addresses
都曾经有
@LazyToOne(value = LazyToOneOption.NO_PROXY)
注释。

@Data
@Entity
@Audited
@Table(name = "COUNTRY")
@EntityListeners(AuditingEntityListener.class)
public class Country implements Serializable {
    @Id
    @Column(name = "id", nullable = false, length = 19)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;
}
@Data
@Entity
@Audited
@Table(name = "ADDRESS")
@EqualsAndHashCode(callSuper = true)
public class Address {
    @Id
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(targetEntity = Country.class, fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "country_id", referencedColumnName = "id", nullable = false, foreignKey = @ForeignKey(name = "fk_country"))
    private Country country;

    @Column(name="street", nullable = false)
    private String street;
}

对于

Person
Country
我有一个简单的 Rest 存储库,如下所示。
Address
没有存储库。

@RepositoryRestResource(collectionResourceRel = "person", path = "person")
public interface PersonRepository extends JpaRepository<Person, Long> {
}

例如,我有以下

Person

{
    "id": 1,
    "name": "John Smith",
    "birthCountry": {
        "id": 10,
        "name": "United States"
    },
    "addresses": [{
        "id": 100,
        "country": {
            "id": 10,
            "name": "United States"
        },
        "name": "Wall Street"
    }]
}

当用户选择一个新的国家/地区并修改地址时,我通过 PUT 从客户端收到以下 json。这就是我期望的最终结果:

{
    "id": 1,
    "name": "Oliver Smith",
    "birthCountry": {
        "id": 11,
        "name": "Canada"
    },
    "addresses": [{
        "id": 100,
        "country": {
            "id": 12,
            "name": "Mexico"
        },
        "name": "Avenida Francisco I. Madero"
    }]
}
调用

SimpleJpaRepository.save
,但仅合并原始值的变化。这是数据库中的最终结果:

{
    "id": 1,
    "name": "Oliver Smith",
    "birthCountry": {
        "id": 10,
        "name": "United States"
    },
    "addresses": [{
        "id": 100,
        "country": {
            "id": 10,
            "name": "United States"
        },
        "name": "Avenida Francisco I. Madero"
    }]
}

我可以在sql调试日志中看到Hibernate生成的更新语句包含

id=10
,而不是我从客户端收到的内容。
奇怪的是,当我在 IntelliJ 中调试
SimpleJpaRepository.save
方法并查看调试器视图中的
Person
实体时,我在相关实体中看到了带有
id=null
的新原始值。但是,如果我评估查询相同内容的表达式,代码片段将返回旧值。

java spring hibernate spring-data-jpa spring-data-rest
1个回答
0
投票

这里没有错误。根据 HATEOAS 风格,要更改

birthCountry
对象中的
Person
,您需要向
PUT
发送
/person/1/birthCountry
请求,并引用
Country
对象的地址:

PUT /person/1/birthCountry
Content-Type: text/uri-list

/country/11

有关更多信息,请参阅 Spring Data REST

© www.soinside.com 2019 - 2024. All rights reserved.