学习如何使上一课中创建的一对一关系成为双向的。本课还展示了如何解决JSON的无限递归问题。

现在,我们有一个单向的一对一的映射,这意味着如果我们有一个Twitter账户,我们无法找到拥有该账户的球员的名字。对/profiles的GET请求只能得到PlayerProfile对象,而不是它所关联的Player

然而,如果我们有Player实体,就有可能找到Twitter账户。从对/players的GET请求中可以看出,PlayerProfile实体也被获取了。

对/players和/profiles的GET请求

对/players和/profiles的GET请求

在上一课创建的单向的一对一关系中,Player类保持着这种关系。PlayerProfile类不能看到这个关系的任何变化。为了使这种关系成为双向的,我们需要对PlayerProfile类做一些修改。我们将添加一个字段来引用回到Player类,并添加@OneToOne注解。我们还将添加gettersetter方法来设置PlayerProfile类中的Player值。这将使我们能够从两个方向获取实体。

双向关系

双向关系

双向关系

  1. 为了建立双向关系,我们将在PlayerProfile类中添加一个Player类的字段,并为该字段添加gettersetter方法。这个字段持有对相关的Player实体的引用。

    package io.datajek.databaserelationships.onetoone;
    
    @Entity
    public class PlayerProfile {
        @Id
        @GeneratedValue(GenertionType.IDENTITY)
        private int id;
        private String twitter;
    
        private Player player;
        //add getter and setter for player field.
    
    }
    

    toString方法也需要更新,以包含新增加的Player字段。

  2. 接下来,我们将在Player字段上添加@OneToOne注解。

mappedBy属性

mappedBy@oneToOne注解的一个可选的属性,它指定了拥有该关系的字段的名称。在我们的例子中,它是Player类中的playerProfile字段。mappedBy属性只被放置在关系的对方一侧。拥有者的一方不能有这个属性。

@Entity
public class PlayerProfile {
  @Id
  @GeneratedValue(GenertionType.IDENTITY)
  private int id;
 
  private String twitter;
 
  @OneToOne(mappedBy="playerProfile")
  private Player player;

}

截屏2022-05-26 21.10.58.png

  1. 如果我们访问H2数据库的web控制台(在http://localhost:8080/h2-console,连接URL为jdbc:h2:mem:testdb),我们会看到数据库结构没有变化。如下面的实体关系图所示,player_profile表的主键被存储为player表中的外键。然而在Java方面,我们现在可以使用PlayerProfile实体访问Player实体。

    表结构

    表结构

  2. 为了测试双向关系,我们将使用以下JSON用POST请求创建一个带有嵌套PlayerProfile对象的Playerhttp://localhost8080/players

    {
        "name": "Djokovic",
        "playerProfile": {
            "twitter" : "@DjokerNole"
        }
    }
    

    这个请求的结果是在playerplayer_profile表中分别有两个INSERT请求

    双向关系意味着德约科维奇拥有**@DjokerNole** Twitter账户,反之亦然,@DjokerNole账户属于德约科维奇。如果我们现在向/profiles发送一个GET请求,我们也会得到球员的详细信息。

    对/profiles的GET请求(双向关系)

    对/profiles的GET请求(双向关系)

JSON 无限递归

  1. 此时,你一定在试图访问/profiles时遇到了一个错误。

    当使用双向关系时,当我们试图检索对象时,JSON会抛出一个无限递归的错误。这是因为Player对象包含对PlayerProfile对象的引用,而PlayerProfile对象也包含对Player对象的引用。

    双向关系中的无限递归问题

    双向关系中的无限递归问题

邮递员中的响应看起来是这样的: