JPA中的双向关系



我错过了一些非常基本的东西。下面给出两个实体Department(逆侧)和Employee(拥有侧),它们形成了从DepartmentEmployee的一对多关系。

Department.java

@Entity
@Table(catalog = "testdb", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"department_id"})})
public class Department implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "department_id", nullable = false)
    private Long departmentId;
    @Column(name = "department_name", length = 255)
    private String departmentName;
    @Column(length = 255)
    private String location;
    @OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
    private List<Employee> employeeList = new ArrayList<Employee>(0);
    private static final long serialVersionUID = 1L;
    // Constructors + getters + setters + hashcode() + equals() + toString().
    // No defensive link (relationship) management methods have yet been added to.
    // CascadeType is also kept at a distance for now.
}

Employee.java

@Entity
@Table(catalog = "testdb", schema = "", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"employee_id"})})
public class Employee implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "employee_id", nullable = false)
    private Long employeeId;
    @Column(name = "employee_name", length = 255)
    private String employeeName;
    @JoinColumn(name = "department_id", referencedColumnName = "department_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private Department department;
    private static final long serialVersionUID = 1L;
    // Constructors + getters + setters + hashcode() + equals() + toString().
    // No defensive link (relationship) management methods have yet been added to.
    // CascadeType is also kept at a distance for now.
}

下面给出无状态EJB(使用CMT)中分别执行持久化、合并和删除操作的一些方法。

public List<Employee> persist() {
    Employee employee = new Employee();
    employee.setEmployeeName("a");
    employee.setDepartment(entityManager.getReference(Department.class, 1L));
    entityManager.persist(employee);
    return employee.getDepartment().getEmployeeList();
}
public List<Employee> merge(Employee employee) {
    employee.setEmployeeName("b");
    employee.setDepartment(entityManager.getReference(Department.class, 1L));
    return entityManager.merge(employee).getDepartment().getEmployeeList();
}
public List<Employee> remove(Employee employee) {
    entityManager.remove(entityManager.contains(employee) ? employee : entityManager.merge(employee));
    return entityManager.getReference(Employee.class, employee.getEmployeeId()).getDepartment().getEmployeeList();
}
public Employee getEmployeeById(Long id) {
    return entityManager.find(Employee.class, id);
}

这些方法由关联的应用程序客户机在非事务性环境中依次(一个接一个)调用。

List<Employee> persistedList = employeeSessionBean.persist();
for (Employee employee : persistedList) {
    System.out.println(employee.getEmployeeId() + " : " + employee.getEmployeeName());
}
List<Employee> mergedList = employeeSessionBean.merge(employeeSessionBean.getEmployeeById(23L));
for (Employee employee : mergedList) {
    System.out.println(employee.getEmployeeId() + " : " + employee.getEmployeeName());
}
List<Employee> listAfterRemoving = employeeSessionBean.remove(employeeSessionBean.getEmployeeById(23L));
for (Employee employee : listAfterRemoving) {
    System.out.println(employee.getEmployeeId() + " : " + employee.getEmployeeName());
}

关系逆侧的列表(List<Employee>)自动反映上述每次操作期间的正确状态。

  • 当一个Employee实体被持久化时,它被列在列表上(我没有显式地添加新持久化的Employee实体到相反面的List<Employee>)。
  • 当一个Employee实体被合并时,对该实体所做的更改将自动反映在反向List<Employee>中的相应实体中(我没有显式地更改反向List<Employee>员工列表中持有的相应实体)。
  • 同样,当一个Employee实体被移除时,它也被移除从反向关系的列表中(我不是)

我目前在EcliseLink 2.6.0。为什么我看到这样的行为似乎与以下文本不匹配?

与所有双向关系一样,它是对象模型的和应用程序有责任维护两者之间的关系方向。在JPA中没有魔法,如果您添加或删除到一侧对于集合,您还必须从另一侧添加或删除,参见对象损坏。从技术上讲,数据库将得到更新的所有者端添加/删除,则正确关系,但你的对象模型会不同步可能导致问题。

http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany Bi-directional_Many_to_Many

这意味着在您的特定示例中,如果您更改代码以将员工添加到部门(而不是以其他方式设置部门),那么您将注意到这不会自动为员工设置部门。您必须编写代码来显式地执行此操作。

因此,即使您所展示的特定代码路径确实有效,也并不意味着您可以依赖它。我可以猜测一下为什么会这样——集合是惰性加载的,因为对象是在集合加载之前持久化的,所以它能够从DB中提取正确的数据。

最好的解决方案是听从文档中的建议,在双向关系的两端正确设置状态,不考虑性能方面的考虑(这可以在以后进行微调)。

相关内容

  • 没有找到相关文章

最新更新