上一篇记录了Hibernate的级联操作中的一对多关系,类似于教师和学生的一对多关系,这一篇记录的是Hibernate的级联操作中一对多双向自身关联关系,举例如下图:
在上图中,食物被分为蔬菜类和水果类,蔬菜类下又有西红柿,水果类下又有苹果和橘子,这几个不同的节点都可以用一个类来表示,这就是一对多双向自身关联关系,在代码中我们就把这些节点抽象为一个类Category,该类的代码如下所示:
package com.test.model; import java.util.Set; public class Category { private Integer id; private String name; private Category parentCategory; private Set<Category> childCategories; public Category(String name, Category parentCategory, Set<Category> childCategories) { super(); this.name = name; this.parentCategory = parentCategory; this.childCategories = childCategories; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Category getParentCategory() { return parentCategory; } public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; } public Set<Category> getChildCategories() { return childCategories; } public void setChildCategories(Set<Category> childCategories) { this.childCategories = childCategories; } }Category类中包含一个id和name,然后每个节点有0个或1个父节点,用成员变量parentCategory表示,该变量也是Category类型,若parentCategory为null,则代表跟节点,其次,每个节点可能有多个子节点,在类中就用一个集合表示,childCategories是一个Set集合,里面装的是Category类型的对象。
下面为Category类编写对应的hbm文件,Category.hbm.xml文件的内容如下:
<?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"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="com.test.model.Category" table="category"> <id name="id" type="int"> <column name="id" /> <generator class="increment" /> </id> <property name="name" type="string"> <column name="name" length="20"></column> </property> <set name="childCategories" cascade="all"> <key column="parent_id"></key> <one-to-many class="com.test.model.Category"/> </set> <many-to-one name="parentCategory" class="com.test.model.Category" column="parent_id"></many-to-one> </class> </hibernate-mapping>可以看到,该hbm文件与上一篇中的hbm不同之处在于,它既有one-to-many标签,又有many-to-one标签,证明Category类是一对多双向自身关联的,Category类对应的数据库表如下:
接下来我们编写测试代码,测试hibernate对这种一对多双向自身关联的支持:
package com.test; import java.util.HashSet; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import com.test.model.Category; public class TestMain { private Category foodCategory; private void init(){ foodCategory = new Category("食物", null, new HashSet<Category>()); Category fruitCategory = new Category("水果", null, new HashSet<Category>()); Category vegetableCategory = new Category("蔬菜", null, new HashSet<Category>()); Category appleCategory = new Category("苹果", null, new HashSet<Category>()); Category orangeCategory = new Category("橘子", null, new HashSet<Category>()); Category tomatoCategory = new Category("西红柿", null, new HashSet<Category>()); foodCategory.getChildCategories().add(fruitCategory); foodCategory.getChildCategories().add(vegetableCategory); fruitCategory.getChildCategories().add(appleCategory); fruitCategory.getChildCategories().add(orangeCategory); vegetableCategory.getChildCategories().add(tomatoCategory); fruitCategory.setParentCategory(foodCategory); vegetableCategory.setParentCategory(foodCategory); appleCategory.setParentCategory(fruitCategory); orangeCategory.setParentCategory(fruitCategory); tomatoCategory.setParentCategory(vegetableCategory); } private void test(){ init(); Session session = HibernateSessionFactory.getSession(); Transaction trans = session.beginTransaction(); try { session.save(foodCategory); trans.commit(); } catch (HibernateException e) { e.printStackTrace(); trans.rollback(); } finally { HibernateSessionFactory.closeSession(); } } public static void main(String[] args) { new TestMain().test(); } }
在数据库中,可以看到增加了如下数据:
而我们在代码中,只保存了一个foodCategory对象,hibernate的级联操作自动为我们加入了其他的对象到数据库,执行删除时,我们将上面的代码中的一句:
session.save(foodCategory);注释掉并添加:
session.delete(session.get(Category.class, 1));可以看到控制台的输出如下:
数据库category表中的数据都被删除,这就是Category.hbm.xml文件中配置的cascade="all"这句起的作用
需要注意的是,如果Category中没有默认的构造方法,在执行上面的delete时会报错,因为如果没有默认的构造方法,hibernate框架就无法使用反射机制去创建对象
源码下载点击这里