1

我之前让@PrimaryKeyJoinColumn 工作过,现在我正在尝试使用spring boot,但我不知道我错过了什么,这很奇怪,因为我似乎做对了所有事情:

人物类:

    @Table(name = "PERSON")
@Entity

@Getter
@Setter
public class Person {

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


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

    @OneToOne(cascade = CascadeType.PERSIST)
    @PrimaryKeyJoinColumn
    private Department department;
}

部门类:

    @Table(name = "DEPARTMENT")
@Entity
@Getter
@Setter
public class Department {

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

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


    @OneToOne(mappedBy = "department")
    private Person person;
}

服务等级:

   @Transactional
    public void addPerson() {
        Person person = new Person();
        person.setName("person 1");
        Department department = new Department();
        department.setName("test");
        department.setPerson(person);
        person.setDepartment(department);
        personRepository.save(person);
    }

这就是我在 DB 中得到的: Person 表:

ID   Name
13  person 1

部门表:

ID  Name
18  test

期望的输出:两个 ID 应该相同(Person ID 应该是 18 而不是 13)有什么想法吗?


更新:休眠总是尝试插入没有 ID 的人员,所以如果我从人员 ID 中删除自动增量并尝试插入现有部门的人员,我会得到:

Hibernate: insert into person (name) values (?)

Field 'id' doesn't have a default value

更新 2: 似乎 @PrimaryKeyJoinColumn 不会将 ID 生成处理为部门类,所以我需要使用生成器。我想知道,因为相同的注释在继承中起作用,而对子类的 ID 没有做任何事情。所以我期待一个答案来解释为什么 ID 生成在 Inheritance join 中起作用,而 OneToOne 需要一个生成器

4

1 回答 1

1

尽管只为一个人创建整个部门(部门通常将很多人分组)至少是不好的命名,但我认为您确实在寻找具有共享主键的 OneToOne 关系。

最好的解决方案(最佳内存、速度和维护)是使用@MapsId

@Getter
@Setter
@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "person", fetch = FetchType.LAZY)
    private Department department;
}

@Getter
@Setter
@Entity
public class Department {
    @Id // Note no generation
    private Long id;

    private String name;

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

这里Department 拥有关系(拥有通常意味着它在数据库中具有与FK 的列,但在这里它们只是共享主键)并拥有将其PK 绑定到Person 生成的FK。

请注意,关系是 OneToOne,双向,共享 PK 作为 FK。这被认为是最佳实践,但有一个小缺点,即必须编写一个 getter。:)

资料来源:https ://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

另外——我强烈建议你花几天时间阅读这个网站上的帖子,甚至在设计比几张桌子更大的东西之前实施其中的一些。:)

编辑

我在这里可能错了(我现在确定 - 看看评论),但据我所知,保持 ID 相等并不是 JPA 规定的。它可以指定的基本上是:

“嘿,你们(Person,Department)是兄弟(OneToOne),并且都知道(在 Person 实体中使用 mappedBy="person" 双向)。您将是会生成 ID 的老兄弟(Person 具有 @GeneratedValue),而您将是你应该有相同的。您将使用这些字段(ID,一个生成,第二个不)来连接(@PrimaryKeyJoinColumn)。

我想说的是,仅仅因为你说“这连接了你”,并不意味着它们是同步的——你必须确保它。

现在关于如何确保它 - @MapsId 被认为是最好的。

如果您正在寻找不同的方法,还可以手动将 ID 设置为与 #setDepartment(Department) 中的其他 ID 相同,您可以将 Department 的 ID 设置为与调用 Person 相同(但这仅在所述 Person 已经生成 ID 时才有效,这基本上打破了这个想法)。

我知道的另一个是使用外国生成器策略。

人:

@Id
@GeneratedValue
private long id;

@OneToOne(mappedBy="person")
private Department department;

部门:

@Id
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
private long id;

@OneToOne
@PrimaryKeyJoinColumn
private Person person;

现在 - 这使用特定于休眠的注释,而不是纯 JPA。

于 2018-11-30T22:30:09.467 回答