在hibernate里面调用session的delete方法以后,无论这个被删除的对象有没有被人外键引用到,都可以被删除,并且此时的外键设为null,也就是说他会自动帮我们去查看他被谁引用到了。然后把引用全部去掉后,再把自己删掉。而在JPA里面,如果调用EntityManager.remove方法时,传进去的对象,有被外键引用到,则会失败。因为JPA里面的实现就是直接执行delete语句,也不管他有没有被外键引用,此时,当然会出错了。
测试时候使用的两个类分别如下:
举的例子是部门和员工的关系。一个部门可以有多个员工。然后把部门删掉的时候,员工的部门属性就为null了,不过,按照严谨来说,还是JPA的严谨一些。这样可以防止误操作,呵呵。
部门的实体对象
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.hadeslee.jpaentity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
*
* @author hadeslee
*/
@Entity
@Table(name = "JPADepartment")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "department")
private Set<Person> persons = new HashSet<Person>();
private String deptName;
private String description;
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Person> getPersons() {
return persons;
}
public void setPersons(Set<Person> persons) {
this.persons = persons;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Department)) {
return false;
}
Department other = (Department) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "com.hadeslee.jpaentity.Department[id=" + id + "]";
}
}
人员的实体对象
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.hadeslee.jpaentity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
*
* @author hadeslee
*/
@Entity
@Table(name = "JPAPerson")
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@ManyToOne
private Department department;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Person)) {
return false;
}
Person other = (Person) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "com.hadeslee.jpaentity.Person[id=" + id + "]";
}
}
由于JPA是不需要配置的,代码里面已经包括了注释,所以下面附上Hibernate的映射文件,为了使数据库里面更清楚一些,所以两者使用的表不是同一张表,JPA的表是带JPA前缀的,用@Table这个注释声明了这一点。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hadeslee.jpaentity">
<class name="Department" table="Department">
<id name="id" column="departId" type="long">
<generator class="native"/>
</id>
<property name="deptName"/>
<property name="description"/>
<set name="persons">
<key column="deptId"/>
<one-to-many class="Person"/>
</set>
</class>
<class name="Person" table="Person">
<id name="id" column="personId" type="long">
<generator class="native"/>
</id>
<property name="name"/>
<property name="age"/>
<many-to-one name="department" column="deptId" class="Department"/>
</class>
</hibernate-mapping>
调用JPA的代码如下:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("TestSSH1PU2");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
com.hadeslee.jpaentity.Person p = new com.hadeslee.jpaentity.Person();
p.setAge(26);
p.setName("千里冰封");
com.hadeslee.jpaentity.Department dept = em.find(com.hadeslee.jpaentity.Department.class, Long.valueOf("3"));
System.out.println("找到的dept=" + dept);
em.remove(dept);
em.getTransaction().commit();
调用hibernate的代码如下:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
Department dept = (Department) session.load(Department.class, 2);
session.delete(dept);
session.getTransaction().commit();
最后发现是JPA是不能删除的,而hibernate这边的调用可以删除,一开始我还以为是toplink的实现问题,后来特意把实现改成hibernate的实现,也同样。所以有可能是JPA的要求必须得这样做,不能替我们自动完成一些东西,是利于安全。这可能就是标准和流行的差别吧。呵呵。