【问题标题】:What is the best way to configure Hibernate annotations to manage a collection of historical records?配置 Hibernate 注释以管理历史记录集合的最佳方法是什么?
【发布时间】:2020-08-27 15:58:51
【问题描述】:

我有一个案例,除了 Employee 实体和 Shift 实体之间的 @OneToMany 关系之外,我还有几个 @OneToOne 关系。员工有一个Current Shift、一个Last Shift,以及一组Shifts,它们代表该员工所执行的班次的历史记录。下面的代码显示了我如何设置我的休眠注释来表示这一点。

@Entity
public class Employee {
   @Id
   @Column(name = "EMP_ID")
   private Long id;

   @OneToOne(cascade = {CascadeType.ALL})
   @JoinColumn(name = "CURRENT_SHIFT_ID")
   private Shift currentShift;

   @OneToOne(cascade = {CascadeType.ALL})
   @JoinColumn(name = "LAST_SHIFT_ID")
   private Shift lastShift;

   @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
   @JoinColumn(name = "EMP_ID")
   private List<Shift> shifts;
}
@Entity
public class Shift {
   @Id
   @Column(name = "SHIFT_ID")
   private Long id;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "EMP_ID", nullable = false)
   private Employee employee;

   @Column(name = "START_DATE")
   private Calendar startDate;

   @Column(name = "END_DATE")
   private Calendar endDate;
}

这里有一些示例代码来说明我正在尝试做的事情。

   public void test1(long employeeId) {
      Employee dbEmployee = entityManager.find(Employee.class, employeeId);

      Calendar startDate = Calendar.getInstance();
      Calendar endDate = Calendar.getInstance();

      // create the first shift
      Shift one = new Shift();
      one.setEmployee(dbEmployee);
      one.setStartDate(startDate);
      one.setEndDate(endDate);

      // create the second shift
      Shift two = new Shift();
      two.setEmployee(dbEmployee);
      two.setStartDate(startDate);
      two.setEndDate(endDate);

      // create the third shift
      Shift three = new Shift();
      three.setEmployee(dbEmployee);
      three.setStartDate(startDate);
      three.setEndDate(endDate);

      // add shifts 1-3 to the collection of shifts that the employee just performed
      List<Shift> shifts = new ArrayList<Shift>();
      shifts.add(one);
      shifts.add(two);
      shifts.add(three);
      dbEmployee.setShifts(shifts);

      // set the last shift to shift #2
      dbEmployee.setLastShift(two);

      // set the current shift to shift #3
      dbEmployee.setCurrentShift(three);

      entityManager.merge(dbEmployee);
   }

在上面的 Test1 方法中,我正在为员工创建 1-3 班次并填充班次集合,此外还要指定哪个班次是员工的最后一班和当前的转变。当我对员工执行合并时,生成的数据库表如下所示:

员工表

id:1,currentShiftId:3,lastShiftId:2

轮班表

id: 1, employeeId: 1, startDate:..., endDate:...

id: 2, employeeId: 1, startDate:..., endDate:...

id: 3, employeeId: 1, startDate:..., endDate:...

到目前为止一切看起来都很好......

   public void test2(long employeeId) {
      Employee dbEmployee = entityManager.find(Employee.class, employeeId);

      Calendar startDate = Calendar.getInstance();
      Calendar endDate = Calendar.getInstance();

      // create the fourth shift
      Shift four = new Shift();
      four.setEmployee(dbEmployee);
      four.setStartDate(startDate);
      four.setEndDate(endDate);

      // create the fifth shift
      Shift five = new Shift();
      five.setEmployee(dbEmployee);
      five.setStartDate(startDate);
      five.setEndDate(endDate);

      // create the sixth shift
      Shift six = new Shift();
      six.setEmployee(dbEmployee);
      six.setStartDate(startDate);
      six.setEndDate(endDate);

      // add shifts 4-6 to the collection of shifts that the employee just performed
      List<Shift> shifts = new ArrayList<Shift>();
      shifts.add(four);
      shifts.add(five);
      shifts.add(six);
      dbEmployee.setShifts(shifts);

      // set the last shift to shift #5
      dbEmployee.setLastShift(five);

      // set the current shift to shift #6
      dbEmployee.setCurrentShift(six);

      entityManager.merge(dbEmployee);
   }

但是,当我执行上面创建 4-6 班次的 Test2 方法并对员工执行合并时,结果如下:

员工表

id:1,currentShiftId:6,lastShiftId:5

轮班表

id: 1, employeeId: NULL, startDate:..., endDate:...

id: 2, employeeId: NULL, startDate:..., endDate:...

id: 3, employeeId: NULL, startDate:..., endDate:...

id: 4, employeeId: 1, startDate:..., endDate:...

id: 5, employeeId: 1, startDate:..., endDate:...

id: 6, employeeId: 1, startDate:..., endDate:...

因此,1-3 班与我的员工失去了关联。我知道,由于我正在执行合并,其中只有 Shifts 4-6 在班次列表中,所以休眠正在更新数据库以仅映射这 3 个班次而其他班次变得孤立,但我真正想要的是保持数据库中的那些历史记录。我想可以做到这样的事情;我只是没有做冬眠的权利。任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 你能分享你的服务代码吗?
  • @Ricardo 我已经用代码示例更新了我的帖子,我认为这将有助于说明我正在尝试做的事情。谢谢!

标签: hibernate collections merge one-to-many many-to-one


【解决方案1】:

通过从 Employee 类中删除 @JoinColumn(name = "EMP_ID") 并改为使用 mappedBy 关系属性,我能够获得我想要的行为。

@Entity
public class Employee {
   @Id
   @Column(name = "EMP_ID")
   private Long id;

   @OneToOne(cascade = {CascadeType.ALL})
   @JoinColumn(name = "CURRENT_SHIFT_ID")
   private Shift currentShift;

   @OneToOne(cascade = {CascadeType.ALL})
   @JoinColumn(name = "LAST_SHIFT_ID")
   private Shift lastShift;

   @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, mappedBy = "employee")
   //@JoinColumn(name = "EMP_ID") // this will try to manage the relationship
   private List<Shift> shifts;
}
@Entity
public class Shift {
   @Id
   @Column(name = "SHIFT_ID")
   private Long id;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "EMP_ID", nullable = false)
   private Employee employee;

   @Column(name = "START_DATE")
   private Calendar startDate;

   @Column(name = "END_DATE")
   private Calendar endDate;
}

我的新理解是,当您希望该实体管理关系时,会使用 @JoinColumn 注释。相反,通过使用 mappedBy 属性,我可以指定关系将由反向实体管理。这非常适合我的情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-04
    • 2011-10-23
    • 2018-06-16
    • 1970-01-01
    • 2021-04-24
    • 2011-02-07
    相关资源
    最近更新 更多