班级学生一对多表关联
建立关联关系的话首先至少要有两个表,那就要有两个实体类,通常是一对多的关系,比如学生和班级,可以在其中一个类加入另一个类的实例,比如在学生中包含班级这个类(如果是班级中包含学生的话那应该是一个班级包含一个学生集合)
public class Student { private long id; private String name; private Class c; //学生只有一个班级,多对一 }
映射文件中加入外键声明,多的这个表一定要加
<!--在学生表中插入一个外键--> <many-to-one name="c" column="classId" class="com.java1234.model.Class" cascade="save-update"></many-to-one>
一的这边也可以声明和多的之间的关联(不是必要)
//类 public class Class { private long id; private String name; private Set<Student> students=new HashSet<Student>(); } //映射文件 <!-- 因为是一对多,所以class表不会多出下面字段,只是建立一种关联而已,不写也可以(写了的话获取班级的同时会自动获取学生集合),但学生表那边一定要写 --> <set name="students" cascade="save-update" inverse="true"> <!-- 加上save-update可以在只保存class的情况下顺便保存student;加上inverse就能在多的一端维护外键;加上cascade="delete"可以进行级联删除 --> <key column="classId"></key> <!-- 外键名 --> <one-to-many class="com.java1234.model.Student"/> </set>
比如上面这个set集合如果不设置的话,那么下面打印的将是0,因为班级获取不到学生
public void testInversse() { Class c=(Class)session.get(Class.class, Long.valueOf(1)); Set<Student> students=c.getStudents(); System.out.println(students.size()); }
最后插入数据的时候要在学生中设置好班级
Class c=new Class(); c.setName("08计本"); session.save(c); Student s1=new Student(); s1.setName("张三"); s1.setC(c); Student s2=new Student(); s2.setName("李四"); s2.setC(c); session.save(s1); session.save(s2);
经过上面学生类和学生映射文件这两步,学生这个表就会自动关联到班级表的主键。
级联
学生映射文件中,在
标签里面,cascade默认是“none”,假如我们希望在持久化多的一端时自动级联保存和更新一的一端,我们可以把cascade设置成“save-update”。那么这个class自己不保存也可以跟着引用了它的student保存下来。反过来,在班级映射文件中加入该标签,则可以使student随着class保存而保存。 Class c=new Class(); c.setName("08计本"); // session.save(c); 不保存,在<many-to-one>标签中加个属性cascade属性即可随多的一方(Student)保存 Student s1=new Student(); s1.setName("张三"); s1.setC(c); Student s2=new Student(); s2.setName("李四"); s2.setC(c); session.save(s1); session.save(s2);
inverse属性
剪除多余hql,提高性能
<set name="students" cascade="save-update" inverse="true"> <!-- 加上save-update可以在只保存class的情况下顺便保存student;加上inverse就能在多的一端维护外键;加上cascade="delete"可以进行级联删除 --> <key column="classId"></key> <!-- 外键名 --> <one-to-many class="com.java1234.model.Student"/> </set>
比如上面班级配置文件中的inverse属性,加上之后可以提高以下程序的性能
//先添加两条没有关联的数据 @Test public void testAdd() { Class c=new Class(); c.setName("09计本"); Student s1=new Student(); s1.setName("王五"); session.save(c); session.save(s1); } //把这两条数据查出来之后再建立联系 @Test public void testInversse() { Class c=(Class)session.get(Class.class, Long.valueOf(1)); Student s=(Student)session.get(Student.class, Long.valueOf(1)); //加了inverse之后可以使第二行不生效(因为它本来就没用,除了多一句多余的hql拖慢性能)提高性能,一般都是在多的一端保存即可 s.setC(c); //在学生中添加班级,会在学生表中增加班级外键 c.getStudents().add(s); //在班级中添加学生,会在学生表中增加学生外键 //这样就会生成hql,在这个学生中加入这个班级的外键 }
级联删除
删除被关联的表时顺便删除父表
/* * 这样运行应该是报错的,因为class表被关联,加上属性cascade="delete"后才能进行级联删除,将学生表记录一并删掉 */ @Test public void testDeleteClassCascade() { Class c=(Class)session.get(Class.class, Long.valueOf(1)); session.delete(c); }
自身关联
自身字段关联自身字段,比如下面一个菜单的例子
数据库
//类
public class Node {private long id; private String name; private Node parentNode; //父节点 private Set<Node> childNodes=new HashSet<Node>(); //子节点
}
//映射文件
//保存数据
@Test
public void testSaveMenu() {Node node=new Node(); node.setName("根结点"); Node subNode1=new Node(); subNode1.setName("子结点1"); Node subNode2=new Node(); subNode2.setName("子结点2"); subNode1.setParentNode(node); subNode2.setParentNode(node); session.save(subNode1); session.save(subNode2);
}
代码实例:eclipse->HibernateCrud