【发布时间】:2021-12-17 23:06:13
【问题描述】:
我有三个班级:WorkPosition、Employee 和 EmployeeCode。员工代表在某处工作的人,员工在工作中可以有很多(工作)职位,员工代码代表员工(一个或多个代码)。对于每个 WorkPosition,必须分配一个默认的 EmployeeCode(字段defaultCode),如果员工有任何代码,则显示哪个代码代表该职位的员工。
-
Employee->WorkPosition是一对多的关系 -
Employee->EmployeeCode是一对多的关系 -
EmployeeCode->WorkPosition是一对多的关系
WorkPosition类:
@Entity
@Table(name = "work_position")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class WorkPosition{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@NotNull
private Employee employee;
@ManyToOne(fetch = FetchType.LAZY)
private EmployeeCode defaultCode;
// other fields, getters, setters, equals and hash ...
Employee类:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@OneToMany(mappedBy = "employee", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<EmployeeCode> employeeCodes;
@OneToMany(mappedBy = "employee", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<WorkPosition> workPositions;
// other fields, getters, setters, equals and hash ...
EmployeeCode类:
@Entity
@Table(name = "employee_code")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class EmployeeCode {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@NotNull
private Employee employee;
@OneToMany(mappedBy = "defaultCode", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<WorkPosition> defaultCodes;
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof EmployeeCode)) {
return false;
} else {
return this.id != null && this.id.equals(((EmployeeCode)o).id);
}
}
// other fields, getters, setters, hash ...
因此,在我的示例中,一个员工的 WorkPositions 之间的唯一区别是 defaultCode,它可能在 WorkPositions 之间有所不同。
我有一个表单,我可以在其中操作与 WorkPosition 相关的所有数据。例如,我可以更改 WorkPosition 的 defaultCode 和/或删除 EmployeeCode。当我保存表单时,我必须检查是否删除了一个 EmployeeCode,该 EmployeeCode 设置为与保存的 WorkPosition 相关的任何 WorkPositions 的 defaultCode。如果是这样,我重新分配它,否则我将无法删除 EmployeeCode,因为我会得到一个 ConstraintViolationException,因为 WorkPosition 仍将引用我希望删除的 EmployeeCode。
假设我有一个员工,有两个员工代码(EC1 和 EC2)和两个工作岗位(WP1 和 WP2)。 WP1 的默认代码为 EC1,WP2 的默认代码为 EC2。我保存了 WP1 的表格,但我没有删除任何内容。为了检查相关 WorkPosition (WP2) 的 defaultCode (EC2) 是否仍然存在,我遍历所有剩余代码(savedWorkPosition.getEmployeeCodes(),其中 savedWorkPosition 等于 WP1)并检查它是否仍然包含 defaultCode(relatedWorkPosition.getDefaultCode(),其中relatedWorkPosition 是从 db 查询并引用 EC2)。
newDefaultCode = savedWorkPosition.getEmployeeCodes() // [EC1, EC2]
.stream()
.filter(code -> code.equals(relatedWorkPosition.getDefaultCode()))
.findFirst()
.orElseGet(() -> ...);
但是,equals()(查看上面的 EmployeeCode 类)返回 false。调试equals方法的时候发现参数对象(EC2)的id是null。当我在等号之前注销过滤器调用中的 id 时,我得到了正确的 id。我可以做.filter(code -> code.getId().equals(relatedWorkPosition.getDefaultCode().getId())) 并且它有效,但这似乎是错误的。 为什么equals方法中的id为空?
我认为这可能是在持久性上下文中对实体的状态做一些事情,而 Hibernate 做了一些我不理解的事情。我使用了this answer 的一些帮助来注销实体的状态:
-
entityManager.contains(relatedWorkPosition.getDefaultCode())返回true -
entityManagerFactory.getPersistenceUnitUtil().getIdentifier(relatedWorkPosition.getDefaultCode())返回正确的 id。 -
entityManager.contains(<any code in savedWorkPosition.getEmployeeCodes()>)返回false -
entityManagerFactory.getPersistenceUnitUtil().getIdentifier(<any code in savedWorkPosition.getEmployeeCodes()>)返回正确的 id。
【问题讨论】:
-
作为建议,不要在
@Entity上实现 equals -
我看到你在集合上使用缓存。确保在添加/删除子实体时更新关系
标签: java hibernate jpa spring-data-jpa