首页 > 解决方案 > 共享主键但想单独管理/保存实体?

问题描述

注意:我是一个休眠新手。

我目前正在尝试在 spring 中为具有相同主键和 OneToOne 关系的 2 个实体建模。

表格1 :

CREATE TABLE person (
id uuid NOT NULL,
name varchar(10000),
CONSTRAINT pk_person_id PRIMARY KEY (id)
)

表 2:

CREATE TABLE nickname (
id uuid NOT NULL,
nick varchar(10000),
CONSTRAINT pk_nickname_id PRIMARY KEY (id),
CONSTRAINT fk_person_id FOREIGN KEY (id) REFERENCES person(id) ON DELETE CASCADE
)

Java 类:

@Getter
@Setter
@NoArgsConstructor
@Entity
@ToString
@Table(name = "Person")
public class Person {

  @Id
  private UUID id;

  @Column(name = "name")
  private String name;
}

@Getter
@Setter
@NoArgsConstructor
@Entity
@ToString
@Table(name = "person")
public class NickName {

  @Id
  private UUID id;

  @Column(name = "nick")
  private String nick;

  @MapsId
  @OneToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "id")
  private Person person;
}   

1)我想要的行为是允许单独保存 Person 类的对象,即不将它们保存为调用保存昵称的一部分。

2) 对于 Person 的一个子集,我可能希望创建一个 Nickname。在这个假设的例子中,每个人只能有一个昵称。

3) 保存昵称时,我不希望 person 对象也被保存。可能这个人可能是事先存在的,昵称是后来添加的。我目前在尝试通过 NicknameRepository.save(nickname) 保存昵称对象时遇到一个关于实体已经存在的异常,其中昵称对象是用 nick 和 person 对象初始化的,如果该人已经存在。

4)我确实希望主键 id 相同,并且 id 是来自 Nickname --> Person 的外键

5)我也不想在保存人员对象时保存或添加昵称。

6)当为现有人添加昵称时,我宁愿只传递 Person 的 id 而不是整个对象。目前,我被迫完整地传递 Person 对象。

如果有人可以提供帮助,那就太好了!

标签: javaspringhibernatejpa

解决方案


这里的答案给出了一个很好的例子来说明如何做到这一点。对你来说,它会是这样的:

@Getter
@Setter
@NoArgsConstructor
@Entity
@ToString
@Table(name = "Person")
public class Person {
  @Id
  private UUID id;

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

  @OneToOne(mappedBy="person")
  private NickName nickname;
}

还有你的另一堂课:

@Getter
@Setter
@NoArgsConstructor
@Entity
@ToString
@Table(name = "NickName")
public class NickName {

  @Id
  @Column(name="person_id")
  private UUID id;

  @OneToOne
  @JoinColumn(name="person_id")
  private Person person;

  @Column(name = "nick")
  private String nick;

}  

如果您从休眠开始,我建议保留书签,这是将关系(一对多等)映射到休眠实体的一个很好的备忘单。

一旦您了解了级联类型,也请查看以确保您的实体以您期望的方式持续存在并删除!如果您使用的是 spring,即使为您的存储库编写单元测试也是确保它按您认为的那样工作的一种非常好的方法。

这是一个如何测试它的快速示例(如果您使用存储库和 Spring):

@RunWith(SpringRunner.class)
@DataJpaTest // sets up an in memory h2 database
public class RepositoryTests {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private UserRepository userRepository;

    @Test
    public void createUser() {
        User user = new User("somethingelse.com", "hello")
        user = userRepository.save(user);

        entityManager.flush(); // This forces the transaction to occur

        assertEquals(userCount + 1, userRepository.findAll().size());

        assertEquals(user, userRepository.findByEmail("somethingelse.com").get());
    }    
}

推荐阅读