【问题标题】:jpa persisting the same object with two ownersjpa 将同一个对象与两个所有者保持一致
【发布时间】:2016-07-11 15:57:15
【问题描述】:

如何在数据库中为包含相同对象的两个实体存储相同的表行? 以下说明了我的无效尝试。

@Entity
public class Employee 
  {
  @ManyToOne(cascade=CascadeType.ALL)
  private Department department;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String name;
  ...
  <Getters and setters for all members here>
  ...
  }

@Entity
public class Department 
  {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String name;
  @OneToMany(mappedBy="department")
  private Collection<Employee> employees;
  ...
  <Getters and setters for all members here>
  ...
  }

在 Servlet 中,我尝试以下操作:

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("Anna");
employee2.setDepartment(department);
...
em.persist(employee1);
em.persist(employee2);

当我这样做时,当employee2 被持久化时,我得到一个错误,即部门的主键已经在数据库中,因为它试图第二次添加同一个部门。

如何实现两个员工都指向数据库中的同一行。

我是否必须通过将员工添加到部门来实现这一目标?

我觉得我在这里缺少一些基本的东西。

【问题讨论】:

  • 具体是什么异常,贴出来
  • 我没有看到 Employee 对象被添加到 Department.employees。
  • 缺少从外观上查看 JPA 提供程序的日志...

标签: java database jpa duplicates inverse


【解决方案1】:

如果是外键,我认为您需要在 Employee 类中添加带有部门 id 的连接列关系(使用@JoinColumn)。请参阅此link 了解更多信息。

【讨论】:

  • 但是缺少的 @JoinColumn 注释在这种情况下不会是问题,因为持久性提供程序将使用默认值,即 DEPARTMENT_ID,其中 department 是拥有实体 (Employee) 中的属性,id 是目标实体 (Department) 中的主键.
  • 默认情况下,只有在单向关系的情况下才会使用 JoinTable。不是在双向关系的情况下。参考这个link
  • 我指的不是JoinTable,而是JoinColumn。您可以查看 JPA 2.0 Specification section 2.10.2 以获得详细说明。
【解决方案2】:

在测试了一些示例后,我确定至少有两种方法可以实现这一目标。

第一种方法似乎最直接,即不使用级联(从关系中删除 cascade=CascadeType.ALL)并先插入部门。

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
Employee employee2=new Employee();
employee2.setName("Anna");
...
em.persist(department);
employee1.setDepartment(department);
em.persist(employee1);
employee2.setDepartment(department);
em.persist(employee2);

这是因为 Employee 中的 ManyToOne 关系存储了 Department 表的外键。部门必须先持久化,否则添加员工时外键不存在。

实现这一点的另一种方法是将级联放在反面。

在部门类变化

@OneToMany(mappedby="department")

@OneToMany(mappedby="department",cascade=CascadeType.ALL)

然后以下将起作用:

Department department=new Department();
department.setName("HR");
Employee employee1=new Employee();
employee1.setName("Bob");
employee1.setDepartment(department);
Employee employee2=new Employee();
employee2.setName("Anna");
employee2.setDepartment(department);
...
department.addEmployee(employee1);
department.addEmployee(employee2);
em.persist(department);

这两个都会导致数据库中有两个表

department
ID  NAME
3    HR

employee
ID  NAME DEPARTMENT_ID
20   Bob     3
21   Anna    3

注意:确切的 ID 号可能会有所不同,因为它们是在此处自动生成的。

还有一种方法是让部门为所有者,员工为反向关系并执行类似的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 2019-06-12
    • 1970-01-01
    相关资源
    最近更新 更多