Hibernate一对多、多对多关联映射(经典)

qin52018pp 贡献于2011-04-10

作者 YYS  创建于2009-05-12 13:49:00   修改者YYS  修改于2010-07-24 06:10:00字数19126

文档摘要:
关键词:

Hibernate多对一单向关联(常用的关联模式) 类图: 表结构: 映射文件: hibernate多对一关联映射 关联映射的本质: * 将关联关系映射到数据库,所谓的关联关系是对象模型在内存中的一个或多个引用 会在多的一端加入一个外键,指向一的一端,这个外键是由 中的column属性定义的,如果忽略了这个属性那么默认的外键与实体的属性一致 标签的定义示例: * 理解级联cascade的含义? * 是对象的连锁操作(对增、删、改起作用) 相关测试: public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Group group = new Group(); group.setName("尚学堂"); User user1 = new User(); user1.setName("菜10"); user1.setGroup(group); User user2 = new User(); user2.setName("容祖儿"); user2.setGroup(group); //不能成功保存,抛出TransientObjectException异常 //因为Group为Tran sient状态,oid没有分配值 //persistent状态的对象是不能引用transient状态的对象的 session.save(user1); session.save(user2); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Group group = new Group(); group.setName("尚学堂"); session.save(group); User user1 = new User(); user1.setName("菜10"); user1.setGroup(group); User user2 = new User(); user2.setName("容祖儿"); user2.setGroup(group); //可以正确存储 session.save(user1); session.save(user2); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testSave3() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Group group = new Group(); group.setName("尚学堂"); User user1 = new User(); user1.setName("菜10"); user1.setGroup(group); User user2 = new User(); user2.setName("容祖儿"); user2.setGroup(group); //不会抛出异常,因为采用了cascade属性,所以它会先保存Group //采用cascade属性是解决TransientObjectException异常的一种手段 session.save(user1); session.save(user2); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); User user = (User)session.load(User.class, 3); System.out.println("user.name=" + user.getName()); System.out.println("user.group.name=" + user.getGroup().getName());//非常重要 session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对一主键关联单向 类图: 数据表: 映射文件: idCard (形成外键约束,很重要) 理解one-to-one标签的含义:指示hibernate怎么加载它的关联对象,默认根据主键加载,constrained="true", 表明当前主键上存在一个约束,person的主键作为外键参照了idCard 。如果去掉constrained="true",那么就不会生成外键约束了。 hibernate一对一主键关联映射(单向关联Person---->IdCard) 一对一主键关联映射:让两个实体对象的id保持相同,这样可以避免多余的字段被创建(如:t_person表中就省略了idCard字段这个外键) 相关测试: public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("88888888888888"); Person person = new Person(); person.setName("菜10"); person.setIdCard(idCard); //不会出现TransientObjectException异常 //因为一对一主键关联映射中,默认了cascade属性 session.save(person); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); //原理:把person查上来的主键拿到,然后到t_idCard这张表,比较idCard主键和它相等,把它加载下来,把它放到person的属性idCard里。 Person person = (Person)session.load(Person.class, 1); System.out.println("person.name=" + person.getName()); System.out.println("idCard.cardNo=" + person.getIdCard().getCardNo()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对一主键关联双向 类图: 表结构(跟主键单向关联的一样): 映射文件: idCard (此标签用来在IdCard一端加载person对象) 说明: hibernate一对一主键关联映射(双向关联Person<---->IdCard) 需要在idcard映射文件中加入标签指向person,指示hibernate如何加载person ,默认根据主键加载。 相关测试: public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = (IdCard)session.load(IdCard.class, 1); System.out.println("idcard.cardNo=" + idCard.getCardNo()); System.out.println("idcard.person.name=" + idCard.getPerson().getName()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对一唯一外键关联单向 类图: 表结构(注意:在t_person表中增加了idCard字段): 相关映射: 说明: hibernate一对一唯一外键关联映射(单向关联Person---->IdCard) 一对唯一外键关联映射是多对一关联映射的特例 可以采用标签,指定多的一端的unique=true,这样就限制了多的一端的多重性为一,通过这种手段映射一对一唯一外键关联 相关测试: public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("88888888888888"); Person person = new Person(); person.setName("菜10"); person.setIdCard(idCard); //不能成功保存,因为IdCard是Transient状态 session.save(person); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = new IdCard(); idCard.setCardNo("88888888888888"); session.save(idCard); Person person = new Person(); person.setName("菜10"); person.setIdCard(idCard); session.save(person); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Person person = (Person)session.load(Person.class, 2); System.out.println("person.name=" + person.getName()); System.out.println("idCard.cardNo=" + person.getIdCard().getCardNo()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对一唯一外键关联双向 类图: 表结构: 相关映射: 说明: hibernate一对一唯一外键关联映射(双向关联Person<---->IdCard) 一对一唯一外键关联双向,需要在另一端(idcard),添加标签,指示hibernate如何加载,其关联对象,默认根据主键加载person,外键关联映射中,因为两个实体采用的是person的外键维护的关系,所以不能指定主键加载person,而要根据person的外键加载,所以采用如下映射方式: 相关测试: public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); IdCard idCard = (IdCard)session.load(IdCard.class, 1); System.out.println("idcard.cardNo=" + idCard.getCardNo()); System.out.println("idcard.person.name=" + idCard.getPerson().getName()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对多单向关联 类图: 表结构: 相关映射: 注:因为在Class的类中有个属性Set,但是不知道Set里面放的是什么类型的东西,所以在配置映射文件的时候通过标签来指定Set中元素的类型。 理解标签的作用:在t_student表中增加了一个列classid作为外键(foreign key),参照了t_calss表的主键id。 说明: hihernate一对多关联映射(单向Classes----->Student) 一对多关联映射利用了多对一关联映射原理 多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一 一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多 也就是说一对多和多对一的映射策略是一样的,只是站的角度不同 在一的一端维护关系的缺点: * 如果将t_student表里的classesid字段(外键)设置为非空,则无法保存 * 因为不是在student这一端维护关系,所以student不知道是哪个班的, 所以需要发出多余的update语句来更新关系 相关测试: public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Student student1 = new Student(); student1.setName("10"); session.save(student1); Student student2 = new Student(); student2.setName("祖儿"); session.save(student2); Set students = new HashSet(); students.add(student1); students.add(student2); Classes classes = new Classes(); classes.setName("尚学堂"); classes.setStudents(students); //可以正确保存 session.save(classes); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Classes classes = (Classes)session.load(Classes.class, 1); System.out.println("classes.name=" + classes.getName()); Set students = classes.getStudents(); for (Iterator iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println("student.name=" + student.getName()); } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate一对多双向关联 类图: 表结构: 注:______的部分必须是一样的 说明: hihernate一对多关联映射(双向Classes<----->Student) 一对多双向关联映射: * 在一的一端的集合上使用,在对方表中加入一个外键指向一一端 * 在多一端采用 注意:标签指定的外键字段必须和指定的外键字段一致,否则引用字段的错误 如果在一的一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多的一端来维护关联关系 关于inverse属性: inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签上, 默认inverse为false,所以我们可以从一的一端和多的一端维护关联关系, 如果设置成inverse为true,则我们只能从多一端来维护关联关系 注意:inverse属性,只影响数据的存储,也就是持久化 inverse和cascade * inverse是关联关系的控制方向 * cascade操作上的连锁反应 相关测试: public void testSave1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Student student1 = new Student(); student1.setName("10"); session.save(student1); Student student2 = new Student(); student2.setName("祖儿"); session.save(student2); Set students = new HashSet(); students.add(student1); students.add(student2); Classes classes = new Classes(); classes.setName("尚学堂"); classes.setStudents(students); //可以正确保存 session.save(classes); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testSave2() {//常用的方法 Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Classes classes = new Classes(); classes.setName("尚学堂"); session.save(classes); Student student1 = new Student(); student1.setName("10"); student1.setClasses(classes); session.save(student1); Student student2 = new Student(); student2.setName("祖儿"); student2.setClasses(classes); session.save(student2); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testSave3() {//用到cascade属性,自动级联。 Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Classes classes = new Classes(); classes.setName("尚学堂"); Student student1 = new Student(); student1.setName("10"); student1.setClasses(classes); Student student2 = new Student(); student2.setName("祖儿"); student2.setClasses(classes); Set students = new HashSet(); students.add(student1); students.add(student2); classes.setStudents(students); //可以正确保存 session.save(classes); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Classes classes = (Classes)session.load(Classes.class, 1); System.out.println("classes.name=" + classes.getName()); Set students = classes.getStudents(); for (Iterator iter=students.iterator(); iter.hasNext();) { Student student = (Student)iter.next(); System.out.println("student.name=" + student.getName()); } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Student student = (Student)session.load(Student.class, 1); System.out.println("student.name=" + student.getName()); System.out.println("student.classes.name=" + student.getClasses().getName()); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate多对多单向关联 类图: 表结构: 相关映射: 注:table="t_user_role"指明第三方表的名字为t_user_roles,key column="userid"指明其中的一列(作为外键关联到表t_user的主键id),column="roleid"指明其中的另一列(作为外键关联到表t_role的主键id)。 在设计数据库表t_user_role时把(userid,roleid)设置为联合主键。 相关测试: public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Role r1 = new Role(); r1.setName("数据录入人员"); session.save(r1); Role r2 = new Role(); r2.setName("商务主管"); session.save(r2); Role r3 = new Role(); r3.setName("大区经理"); session.save(r3); User u1 = new User(); u1.setName("10"); Set u1Roles = new HashSet(); u1Roles.add(r1); u1Roles.add(r2); u1.setRoles(u1Roles); User u2 = new User(); u2.setName("祖儿"); Set u2Roles = new HashSet(); u2Roles.add(r2); u2Roles.add(r3); u2.setRoles(u2Roles); User u3 = new User(); u3.setName("杰伦"); Set u3Roles = new HashSet(); u3Roles.add(r1); u3Roles.add(r2); u3Roles.add(r3); u3.setRoles(u3Roles); session.save(u1); session.save(u2); session.save(u3); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); User user = (User)session.load(User.class, 1); System.out.println(user.getName()); for (Iterator iter=user.getRoles().iterator(); iter.hasNext();) { Role role = (Role)iter.next(); System.out.println(role.getName()); } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } Hibernate多对多双向关联 类图: 表结构: 相关映射: 说明: hibernate多对多关联映射(双向User<---->Role) 映射方法: table属性值必须和单向关联中的table属性值一致 中column属性值要与单向关联中的标签中的column属性值一致 在中的column属性值要与单向关联中标签的column属性值一致 相关测试: public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Role r1 = new Role(); r1.setName("数据录入人员"); session.save(r1); Role r2 = new Role(); r2.setName("商务主管"); session.save(r2); Role r3 = new Role(); r3.setName("大区经理"); session.save(r3); User u1 = new User(); u1.setName("10"); Set u1Roles = new HashSet(); u1Roles.add(r1); u1Roles.add(r2); u1.setRoles(u1Roles); User u2 = new User(); u2.setName("祖儿"); Set u2Roles = new HashSet(); u2Roles.add(r2); u2Roles.add(r3); u2.setRoles(u2Roles); User u3 = new User(); u3.setName("杰伦"); Set u3Roles = new HashSet(); u3Roles.add(r1); u3Roles.add(r2); u3Roles.add(r3); u3.setRoles(u3Roles); session.save(u1); session.save(u2); session.save(u3); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); User user = (User)session.load(User.class, 1); System.out.println(user.getName()); for (Iterator iter=user.getRoles().iterator(); iter.hasNext();) { Role role = (Role)iter.next(); System.out.println(role.getName()); } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Role role = (Role)session.load(Role.class, 1); System.out.println(role.getName()); for (Iterator iter=role.getUsers().iterator(); iter.hasNext();) { User user = (User)iter.next(); System.out.println(user.getName()); } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } } 2010-7-24完稿

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档