JPA @OneToOne共享 ID -- 我能做得更好吗?

2022-08-31 13:19:18

我正在使用一个我宁愿不更改的现有架构。该架构在表 Person 和 VitalStats 之间具有一对一关系,其中 Person 具有主键,而 VitalStats 使用与其主键和 Person 的外键相同的字段,这意味着其值是 Person 的相应 PK 的值。

这些记录是由外部进程创建的,我的JPA代码永远不需要更新VitalStats。对于我的对象模型,我希望我的 Person 类包含一个 VitalStats 成员,但是:

当我尝试时

@Entity
public class Person{
    private long id;
    @Id
    public long getId(){ return id; }

    private VitalStats vs;
    @OneToOne(mappedBy = “person”)
    public VitalStats getVs() { return vs; }
}

@Entity
    public class VitalStats{
     private Person person;
    @OneToOne
    public Person getPerson() { return person; }
}

我有一个问题,VitalStats缺少@Id,这不适用于@Entity。

如果我尝试

@Id @OneToOne
public Person getPerson() { return person; }

这解决了@Id问题,但要求Person是可序列化的。我们再回到这个问题上来。

我可以制作VitalStats@Embeddable并通过@ElementCollection将其连接到Person,但随后必须将其作为集合进行访问,即使我知道只有一个元素。可行,但两者都有点烦人,有点令人困惑。

那么,是什么阻止了我说 Person 实现了 Serializable 呢?真的,除了我喜欢代码中的所有内容都是有原因的,而且我看不到任何逻辑,这使得我的代码可读性降低。

与此同时,我只是用一个长 personId 替换了 VitalStats 中的 Person 字段,并使 VitalStats @Id,所以现在@OneToOne工作正常。

所有这些解决方案(在我看来)似乎是一个直截了当的问题,都有点笨拙,所以我想知道我是否错过了什么,或者是否有人可以至少向我解释为什么Person必须是可序列化的。

断续器


答案 1

要使用共享主键映射一对一关联,请使用和注释。@PrimaryKeyJoinColumn@MapsId

休眠参考文档的相关部分:

主要键加入列

PrimaryKeyJoinColumn 批注确实表示实体的主键用作关联实体的外键值。

地图标识

MapsId 注释要求 Hibernate 从另一个关联实体复制标识符。在Hibernate术语中,它被称为外部生成器,但JPA映射读起来更好,并且受到鼓励

人.java

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "person_id")
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private VitalStats vitalStats;       
}

VitalStats.java

@Entity
public class VitalStats 
{
    @Id @Column(name="vitalstats_id") Long id;

    @MapsId 
    @OneToOne(mappedBy = "vitalStats")
    @JoinColumn(name = "vitalstats_id")   //same name as id @Column
    private Person person;

    private String stats;
}

人员数据库表

CREATE TABLE  person (
  person_id   bigint(20) NOT NULL auto_increment,
  name        varchar(255) default NULL,
  PRIMARY KEY  (`person_id`)
) 

VitalStats Database Table

CREATE TABLE  vitalstats 
(
  vitalstats_id  bigint(20) NOT NULL,
  stats          varchar(255) default NULL,
  PRIMARY KEY  (`vitalstats_id`)
)

答案 2

在我的情况下,这是诀窍:

父类:

public class User implements Serializable {
  private static final long serialVersionUID = 1L;

  /** auto generated id (primary key) */
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(unique = true, nullable = false)
  private Long id;

  /** user settings */
  @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
  private Setting setting;
}

儿童班:

public class Setting implements Serializable {
  private static final long serialVersionUID = 1L;

  /** setting id = user id */
  @Id
  @Column(unique = true, nullable = false)
  private Long id;

  /** user with this associated settings */
  @MapsId
  @OneToOne
  @JoinColumn(name = "id")
  private User user;
}

推荐