【问题标题】:Using Spring-Data-Rest, how to update FK on both sides of OneToOne relationship from one REST call?使用 Spring-Data-Rest,如何从一个 REST 调用更新 OneToOne 关系双方的 FK?
【发布时间】:2020-03-06 03:20:38
【问题描述】:

我有一个 Spring-Boot 应用程序

  • spring-boot-starter-data-rest
  • spring-boot-starter-data-jpa
  • h2

我有这样一对一关系的实体:

@Entity
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long key;

    @OneToOne(cascade = ALL)
    @JoinColumn(name = "party")
    private Party party;

    @Column
    private String street;

    ....
}
@Entity
public class Party {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long key;

    @Column
    private String name;

    @OneToOne(cascade = ALL)
    @JoinColumn(name  = "address")
    private Address address;

    ...

}

以及每个实体的存储库:

@RepositoryRestResource
public interface AddressRepository extends JpaRepository<Address, Long> { }
@RepositoryRestResource
public interface PartyRepository extends JpaRepository<Party, Long> { }

我为每个实体创建一个实例:

curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{ "name": "John Smith" }' \
     http://localhost:8080/parties
curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{ "street": "456 main st" }' \
     http://localhost:8080/addresses

在地址实例上,我创建了一个 HATEOAS 关联方:

curl -X PUT \
     -H 'Content-Type: text/uri-list' \
     -d http://localhost:8080/parties/1 \
     http://localhost:8080/addresses/1/party

当我检查地址的关联时:

curl -X GET http://localhost:8080/addresses/1/party -i

我看到了正确的派对:

HTTP/1.1 200 
{
  "key" : 1,
  "name" : "John Smith",
  ....
}

但是,当我检查地址的关联时:

curl -X GET http://localhost:8080/parties/1/address -i

它不存在:

HTTP/1.1 404 

如何使用 Spring-Data-Rest 从一次调用中创建两个关联?

【问题讨论】:

  • 你能告诉我们你在聚会中保存的java代码吗
  • 就在上面,保存由 JpaRepository 代理并作为 POST 公开。
  • 它不存在,实际上,我想看看你在哪里调用repository.save,我怀疑你保存聚会时没有填充地址,理想情况下,当你保存聚会地址时也应该保存
  • 除了@SpringBootApplication 类有一个main 方法,这是整个应用程序(减去getter/setter)。无需手动调用 repository.save —— 这是由 spring-data-rest 自动代理到 REST 端点的。
  • 好的,刚刚意识到你在使用@RepositoryRestResource,以为你在使用@Repository

标签: java spring-boot spring-data-jpa spring-data-rest spring-hateoas


【解决方案1】:

你需要像下面这样执行你的 curl

curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{ "name": "John Smith" , "address":{ "street": "456 main st" }}' \
     http://localhost:8080/parties

我在 Entity 中做了一些小改动

@Entity
public class Party implements Serializable{


    private static final long serialVersionUID = 1735292011581348691L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long key;

    @Column
    @JsonProperty("name")
    private String name;

    @JsonProperty("address")
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name  = "address")
    private Address address;


}

@Entity
public class Address implements Serializable {
private static final long serialVersionUID = -7468012139122259209L;


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long key;


    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "party")
    private Party party;

    @JsonProperty("street")
    @Column
    private String street;

}

工作正常,当我测试时。它保存在两个表中

卷曲获取

curl -X  http://localhost:8080/parties/1

【讨论】:

  • 我不想在创建时创建关联。我想创建实体,然后稍后应用一个关联,该关联应该应用于两个实体的 FK。无论我将关联应用于来自一方的地址还是来自地址的一方,我都希望两个 FK 都会更新,但我观察到只应用了一个更新。
  • 好吧,我想,你可以只保留一侧。假设如果你必须使用 sql 添加数据,你最终会写两个插入和两个更新
  • 我找到了解决方案,请看我的回答
  • 很好,只是想念这一点,尽管我使用相同的方法来维护上次更新的实体。
【解决方案2】:

我在Party 班级中使用@PrePersist@PreUpdate 找到了解决方案:

@Entity
public class Party {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long key;

    @Column
    private String name;

    @OneToOne(cascade = ALL)
    @JoinColumn(name  = "address")
    private Address address;

    @PrePersist
    @PreUpdate
    public void updateAddressAssociation() {
        if (address != null)
            address.setParty(this);
    }

}

这是我的应用流程:

  1. 创建地址:
curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{ "street": "456 main st" }' \
     http://localhost:8080/addresses
  1. 创建派对
curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{ "name": "John Smith" }' \
     http://localhost:8080/parties
  1. 将地址与方关联
curl -X PUT \
     -H 'Content-Type: text/uri-list' \
     -d http://localhost:8080/parties/1 \
     http://localhost:8080/addresses/1/party
  1. 确认一方有地址关联
curl http://localhost:8080/parties/1/address
  1. 确认地址有党组织
curl http://localhost:8080/addresses/1/party

【讨论】:

    猜你喜欢
    • 2016-04-17
    • 2018-01-04
    • 2019-01-07
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2015-08-08
    • 2017-10-16
    • 1970-01-01
    相关资源
    最近更新 更多