@PrimaryKeyJoinColumn 没有选择共享密钥
@PrimaryKeyJoinColumn not picking the shared key
我之前让@PrimaryKeyJoinColumn 工作,现在我正在尝试 spring 引导,但我不知道我错过了什么,这很奇怪,因为我似乎做对了所有事情:
人class:
@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;
}
部门class:
@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;
}
服务 class :
@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);
}
这就是我在数据库中得到的:
人 table :
ID Name
13 person 1
部门table:
ID Name
18 test
期望的输出:两个 ID 应该相同(Person ID 应该是 18 而不是 13)
有什么想法吗?
更新:
hibernate 总是尝试插入没有 ID 的人,所以如果我从 Person ID 中删除自动递增并尝试插入现有部门的人,我得到:
Hibernate: insert into person (name) values (?)
Field 'id' doesn't have a default value
更新二:
似乎 @PrimaryKeyJoinColumn 不会像部门 class 那样处理 ID 生成,所以我需要使用生成器。我想知道,因为相同的注释在 Inheritance joined 中起作用,而没有对 subclass 的 ID 做任何事情。所以我期待一个答案来解释为什么 ID 生成在 Inheritance joined 中起作用,而 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 指定的内容。它可以指定的基本上是:
"Hey, you guys (Person, Department) are brothers (OneToOne) and both know it (bidirectional with mappedBy="person" 在 Person 实体中)。你会生成 ID(Person 有@GeneratedValue)的老兄弟,你会更年轻,应该有相同的。你将使用那些字段(IDs ,一个生成,第二个不生成)连接(@PrimaryKeyJoinColumn)。
我想说的是,仅仅因为你说 "this connects you",并不意味着它们是同步的 - 你必须确保它。
现在关于如何确保它 - @MapsId 被认为是最好的。
如果您正在寻找不同的方法,也可以使用#setDepartment(Department) 手动将 ID 设置为与其他方法相同,您可以将部门的 ID 设置为与调用人员相同(但这仅在所述人员已经生成了一个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;
现在 - 这个 使用特定于 hibernate 的注释 而不是纯 JPA。
我之前让@PrimaryKeyJoinColumn 工作,现在我正在尝试 spring 引导,但我不知道我错过了什么,这很奇怪,因为我似乎做对了所有事情:
人class:
@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;
}
部门class:
@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;
}
服务 class :
@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);
}
这就是我在数据库中得到的: 人 table :
ID Name
13 person 1
部门table:
ID Name
18 test
期望的输出:两个 ID 应该相同(Person ID 应该是 18 而不是 13) 有什么想法吗?
更新: hibernate 总是尝试插入没有 ID 的人,所以如果我从 Person ID 中删除自动递增并尝试插入现有部门的人,我得到:
Hibernate: insert into person (name) values (?)
Field 'id' doesn't have a default value
更新二: 似乎 @PrimaryKeyJoinColumn 不会像部门 class 那样处理 ID 生成,所以我需要使用生成器。我想知道,因为相同的注释在 Inheritance joined 中起作用,而没有对 subclass 的 ID 做任何事情。所以我期待一个答案来解释为什么 ID 生成在 Inheritance joined 中起作用,而 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 指定的内容。它可以指定的基本上是:
"Hey, you guys (Person, Department) are brothers (OneToOne) and both know it (bidirectional with mappedBy="person" 在 Person 实体中)。你会生成 ID(Person 有@GeneratedValue)的老兄弟,你会更年轻,应该有相同的。你将使用那些字段(IDs ,一个生成,第二个不生成)连接(@PrimaryKeyJoinColumn)。
我想说的是,仅仅因为你说 "this connects you",并不意味着它们是同步的 - 你必须确保它。
现在关于如何确保它 - @MapsId 被认为是最好的。
如果您正在寻找不同的方法,也可以使用#setDepartment(Department) 手动将 ID 设置为与其他方法相同,您可以将部门的 ID 设置为与调用人员相同(但这仅在所述人员已经生成了一个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;
现在 - 这个 使用特定于 hibernate 的注释 而不是纯 JPA。