具有共享ID的JPA @OneToOne - 我可以做得更好吗?

时间:2011-07-26 16:28:32

标签: java jpa one-to-one

我正在使用一个我不想改变的现有架构。表格Person和VitalStats之间具有一对一的关系,其中Person有一个主键,VitalStats使用相同的字段作为其主键和它的外键到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是Serializable。我们会回过头来看。

我可以制作VitalStats @Embeddable并通过@ElementCollection将它连接到Person,但是它必须作为集合访问,即使我知道只有一个元素。可行,但既有点烦人又有点混乱。

那么是什么阻止我只是说Person实现了Serializable?没什么,真的,除了我喜欢我的代码中的所有东西都是有原因的,并且我看不到任何逻辑,这使得我的代码不那么可读。

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

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

TIA

2 个答案:

答案 0 :(得分:86)

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

Hibernate参考文档的相关部分:

PrimaryKeyJoinColumn

  

PrimaryKeyJoinColumn注释确实说明了主键   该实体用作关联实体的外键值。

MapsId

  

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

<强> Person.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数据库表

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

答案 1 :(得分:15)

就我而言,这就是诀窍:

家长班:

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;
}