假设我成功创建了一个数据库表和相应的java实体。该实体代表 worker 可能担任的职位。作为主键,它使用递增的 ID 号而不是业务键:
@Entity
public class Position {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String positionName;
private String description;
// getters and setters
}
假设该公司有三个职位:
id: 1 positionName: "Teacher" description: "To be edited"
id: 2 positionName: "Janitor" description: "To be edited"
id: 3 positionName: "Chairman" description: "To be edited"
现在我们有一个 Employee 实体类:
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String surname;
// HERE THE PROBLEMATIC RELATION
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "positionId")
public Position position;
// getters and setters
}
正如您可能认为的,Employee 实体的这种设计会导致问题。 当使用 Spring 以 JSON 格式为新员工进行 POSTing 时,我发送以下数据以保留具有教师职位的新员工 Ellen Johansson:
{
"name" : "Ellen",
"surname" : "Johansson",
"position" : {
"id" : 1
}
}
正如您可能猜测的那样,此 POSTing 会覆盖 id = 1 的现有位置,并且由于positionName 和positionDesription 均为空,我最终得到编辑后的位置表,如下所示:
id: 1 positionName: null description: null
id: 2 positionName: "Janitor" description: "To be edited"
id: 3 positionName: "Chairman" description: "To be edited"
如何设计我的员工职位关系,以便:
在持久化新员工时声明职位 ID 就足够了,但这不会覆盖预定义职位表中的现有行,并且如果职位表中不存在职位 id 描述的行,也不会添加新行?
*我猜 OneToOne 关系正在使一切崩溃,我应该使用一些 @Embedded 关系。
最佳答案
首先,它可能应该是ManyToOne:通常有多个员工从事相同的工作。
第二:你混合了三个完全不同的方面:
- 应如何设计持久性模型,
- 应如何设计您的 HTTP API,
- 如何将员工分配到现有职位
关于第一点,除了 OneToOne 应该是 ManyToOne 之外,您已经了解了。
关于第二点:您不想接受在 API 中担任职位的员工。您想要接受创建 Employee 所需的数据(可以等于、小于或大于 Employee 实体包含的数据),以及了解其位置所需的数据,即职位的 ID。因此,不要使用持久性 JPA 实体来表示 API 的输入。使用专用的 EmployeeCreationCommand 类,其中包含客户端应发送的内容(不多不少),以便创建员工:姓名、职位 ID。
关于第三点:现在您收到了要创建的员工的信息,包括其职位的ID,您需要
- 获取由接收到的位置 ID 标识的
Position
实体 - 创建一个 Employee 实例,其中填充了命令中收到的信息,并链接到您在上一步中获得的 Position 实例
- 留住该员工
关于java - 如何设计实体以存储预定义字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57622441/