我错过了一些非常基本的东西。下面给出两个实体Department
(逆侧)和Employee
(拥有侧),它们形成了从Department
到Employee
的一对多关系。
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中提取正确的数据。
最好的解决方案是听从文档中的建议,在双向关系的两端正确设置状态,不考虑性能方面的考虑(这可以在以后进行微调)。