@PrimaryKeyJoinColumn 没有选择共享密钥
Posted
技术标签:
【中文标题】@PrimaryKeyJoinColumn 没有选择共享密钥【英文标题】:@PrimaryKeyJoinColumn not picking the shared key 【发布时间】:2018-11-30 20:49:16 【问题描述】:我之前有 @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);
这就是我在数据库中得到的: 人员表:
ID Name
13 person 1
部门表:
ID Name
18 test
期望的输出:两个 ID 应该相同(个人 ID 应该是 18 而不是 13) 有什么想法吗?
更新: hibernate 总是尝试插入没有 ID 的 Person,所以如果我从 Person ID 中删除自动增量并尝试插入具有现有部门的人员,我会得到:
Hibernate: insert into person (name) values (?)
Field 'id' doesn't have a default value
更新 2: 似乎@PrimaryKeyJoinColumn 不会将 ID 生成处理为部门类,所以我需要使用生成器。我想知道,因为相同的注释在继承中起作用,而对子类的 ID 没有做任何事情。所以我期待一个答案来解释为什么 ID 生成在 Inheritance join 中起作用,而 OneToOne 需要一个生成器
【问题讨论】:
Person
中的private long id
应该是private Long id
吗?
@RobertBain 我试过了,同样的问题
您是否也尝试过保存部门?例如。 departmentRepository.save(department)
@RobertBain 是的,我尝试不使用级联并首先保存部门。
@RobertBain 我尝试使用标准的 getter/setter 相同的问题。所需的输出都应具有相同的 ID
【参考方案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/
另外 - 我强烈建议您花几天时间阅读该网站上的帖子,甚至在设计比几张桌子更大的东西之前实施其中的一些帖子。 :)
编辑
我在这里可能错了(我现在确定 - 看看 cmets),但据我所知,保持 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。
【讨论】:
非常感谢。我会尝试的,尽管我知道那个解决方案。我很想知道为什么@primarykeyjoincolumn 不选择部门的ID?我写了这个例子来试试 OneToOne ,这只是示例。你能解释一下为什么它不起作用吗? 这真的归结为 - 一个可以没有其他的存在,哪一个?其中一个必须没有产生价值,并且必须具有将PK其他人的setter。然后归结为使用 MapsId,因为这会强制执行我之前编写的所有内容。如果我们真的在谈论真正的 OneToOne,我会说 PrimaryKeyJoinColumn 是较弱的环节。除非您允许实际的 FK(不是共享的 PK)。 @Erino MapsId 有效,但我仍然不明白为什么 primarykeyjoincolumn 不处理 ID 生成。继承中的相同作品加入,你能解释一下吗? @MohammadKarmi 根据我的知识尽力而为(编辑后的答案)。我的例子被扭转了(我想你想让 Dept 成为父母?)但这仍然是示例代码。 :) 非常感谢,生成器绝对有效,MapsId 也处理ID。但是primarykeyjoincolumn是唯一一个不关心ID的。如果没有答案我会接受这个,以上是关于@PrimaryKeyJoinColumn 没有选择共享密钥的主要内容,如果未能解决你的问题,请参考以下文章
JPA 中的 referencedColumnName 用于啥?
optiona=false导致的问题之Hibernate源码分析