【问题标题】:How does @OnetoOne relationship work in JPA?@OnetoOne 关系如何在 JPA 中工作?
【发布时间】:2014-11-26 22:39:57
【问题描述】:

我正在尝试在两个实体之间建立一对一的映射。一个实体按如下方式维护用户记录:

@Entity
public class ConcreteUser implements User{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String name;
    private String email;
    private int age;
    private SEX sex;
    private String accessLevel;

    public ConcreteUser() {
    }

    public ConcreteUser(String name, String email, int age, SEX sex, String accessLevel) {
        // set class properties
    }

   //
   // Some getter and setter code
   //

我想使用上述实体的主键作为其他实体的外键,它维护其他信息。这是另一个实体的样子:

@Entity
public class SomeOtherEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "SOME_COLUMN_NAME")
    private long recordId;

    //
    // some other private fields here
    //

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private ConcreteUser concreteUser;

    public SomeOtherEntity () {
    }

    // getters and setters etc

我的示例测试用例如下:

@Test
public void testAddSomeOtherEntity() throws Exception {


    /* This is the user, whose primary key will be used as a foreign key in SomeOtherEntity */
    ConcreteUser user = new ConcreteUser(...);


    /* Create a new SomeOtherEntity and assign a ConcreteUser to it */
    SomeOtherEntity d = new SomeOtherEntity();
    d.setConcreteUser(user); /* I doubt if this line has any effect at all */

    // add SomeOtherEntity to table
    /* addSomeOtherEntity is translated to an HTTP request and server responds with added entity  */
    d = myService.addSomeOtherEntity(d); 
    assertNotNull(d);

    /* At this point, the recordId is generated and updated */

    // Check if this entity was added properly
    long recordId = d.getRecordId();
    SomeOtherEntity d2 = myService.getSomeOtherEntityById(recordId);
    assertNotNull(d2);

    /* This test case passes */
    assertEquals(d2.getRecordId(), d.getRecordId()); 

    /* But this test case fails */
    assertEquals(d2.getConcreteUser().getId(), d.getConcreteUser().getId());

}

总之,我创建 SomeOtherEntity 对象,分配一个 ConcreteUser 对象并持久化 SomeOtherEntity 。但是,当我检索 SomeOtherEntity 时,我得到的 ConcreteUser 与我之前分配的不同。特别是,我返回的 ConcreteUser 与“recordId”具有相同的“id”。这不是我所期望的。

我对 Spring 很陌生,我确信我误解了一些东西。截至目前,我认为提前将 ConcreteUser 分配给 SomeOtherEntity 没有任何意义。相反,也许我应该先创建并保留 SomeOtherEntity,然后更新 ConcreteUser? 如果有人可以提供一些建议以及在现实世界中是如何完成的,我将非常感激。提前致谢。

【问题讨论】:

    标签: spring jpa one-to-one


    【解决方案1】:

    在您的 SomeOtherEntity 中,您为 ConcreteUser 指定 @PrimaryKeyJoinColumn 映射。如果你检查the documentation of the annotation,你会发现它说:

    ... 它可以用于 OneToOne 映射,其中的主键 引用实体用作被引用实体的外键 实体

    这意味着 SomeOtherEntity 的主键值被用作 ConcreteUser 的外键值。

    您想改用@JoinColumn 注释。

    【讨论】:

    • 他可能根本不需要@JoinColumn 注释。
    【解决方案2】:

    因此,事实证明,在 Spring 中实现一对一关系有不同的方法。以下是对不同方式的简短而有用的介绍: Hibernate one-to-one mapping using annotations

    这里的问题不是拥有方,而是三者中为一对一映射选择的方法。根据上面提到的文章,@PrimaryKeyJoinColumn 注释用于当您希望两个表的主键匹配时,此处并非如此。 如问题中所述,测试用例失败是因为 Hibernate 基于主键而不是使用 setConcreteUser 分配的 ConcreteUser 实体映射了两个表

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 1970-01-01
      • 1970-01-01
      • 2010-11-29
      • 2020-03-19
      • 2021-05-22
      相关资源
      最近更新 更多