【Hibernate3】(4)关联映射(一)

来源:互联网 发布:ko是什么意思网络用语 编辑:程序博客网 时间:2024/05/31 19:06

一. 多对一单向关联

1. 映射配置

创建Group和Contact两个实体类:
public class Group {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Group [id=" + id + ", name=" + name + "]";}}
public class Contact {private int id;private String name;private Group group;public Group getGroup() {return group;}public void setGroup(Group group) {this.group = group;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Contact [id=" + id + ", name=" + name + ", group=" + group+ "]";}}
配置对应的配置文件:
<hibernate-mapping package="com.thr.hibernate.entity"><class name="Group" table="t_group"><id name="id"><generator class="increment" /></id><property name="name"></property></class></hibernate-mapping>
<hibernate-mapping package="com.thr.hibernate.entity"><class name="Contact" table="t_contact" lazy="true"><id name="id"><generator class="increment" /></id><property name="name" /><many-to-one name="group" column="groupId"></many-to-one></class></hibernate-mapping>
注意这里在配置Contact的配置文件时,使用了<many-to-one>标签,这个就是用来处理多对一的情况的。
测试方法:
public void testMany2One() {Group g = new Group();g.setName("同学");Contact c = new Contact();c.setName("张三");c.setGroup(g);Contact c2 = new Contact();c2.setName("李四");c2.setGroup(g);Contact c3 = new Contact();c3.setName("王五");c3.setGroup(g);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(c);session.save(c2);session.save(c3);session.save(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
我们先保存了Contact对象,然后保存了Group对象,这样子在后台实际情况就是先依次保存Contact对象的时候,它的group字段先赋空,然后在保存Group对象,这时Group就有了id值,之后再更新之前保存的Contact对象,更新group字段为新保存的Group的id。
如果先保存Group对象后再保存3个Contact对象,那么就会先保存Group对象,生成id,然后再一次保存3个Contact对象,赋group字段为保存的Group的id值。
在数据库中保存的方式看起来是比较复杂的,但是我们在操作java代码的时候就会方便许多:
/** * 多对一单向关联 *  */public void testMany2One2() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Contact c = (Contact) session.get(Contact.class, 1);System.out.println(c);System.out.print(c.getGroup());trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
当我们查询出来Contact之后,可以直接使用getGroup取得相关的Group的信息,根本不需要关系数据库中是先取得group的id,然后去根据id去查询的。

2. 延迟加载

/**<span style="white-space:pre"></span> * 延迟加载<span style="white-space:pre"></span> *  */public void testMany2One3() {Contact c = null;Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();c = (Contact) session.get(Contact.class, 1);System.out.println(c.getName());trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}System.out.print(c.getGroup());}
当给group配置lazy="proxy"的时候,执行这段代码就会报错,因为当session关闭的时候还是使用的Contact的代理,所以结尾处找不到Contact对象了,于是报错了。

3. 级联配置

如果我们在保存的时候只保存了Contact对象,而没有保存Group对象,会发生什么呢?
public void testMany2One() {Group g = new Group();g.setName("同学");Contact c = new Contact();c.setName("张三");c.setGroup(g);Contact c2 = new Contact();c2.setName("李四");c2.setGroup(g);Contact c3 = new Contact();c3.setName("王五");c3.setGroup(g);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(c);session.save(c2);session.save(c3);//session.save(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
执行会发现报错了,那么这是为什么呢?因为在保存Contact对象的时候,它有一个group的引用,而这个group的引用此时还不是持久化的,所以会报错。此时要想能继续成功运行,必须在配置文件中配置级联属性:
<many-to-one name="group" cascade="save-update" column="groupId"lazy="false"></many-to-one>
这个意思就是在保存或者更新的时候会进行相关属性的级联操作(保存、更新等),级联的保存还可以设置delete和all。
当我们级联配置的是all的时候,看如下的代码:
public void testMany2One2() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Contact c = (Contact) session.get(Contact.class, 2);session.delete(c);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
执行会发现报错了,因为当删除id为2的Contact的时候,会级联的去删除它所关联的Group对象,但是Group对象不仅仅关联了它一个,还关联了其他的几个Contact对象,所以在删除的时候就报错了。要想正常运行的话,要么修改cascade为none或者删除cascade属性,那么有什么简单点的方法吗?可以的,就是使用离线对象来删除:
public void testMany2One3() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Contact c = new Contact();c.setId(3);session.delete(c);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
哈哈,是不是很简单。

二. 一对多单向关联

1. 映射配置

看一下我们现在的Group类和Contact类:
public class Group {private int id;private String name;/** * 使用set集合保证元素不会出现重复的对象 */private Set<Contact> contacts = new HashSet<Contact>();public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Group [id=" + id + ", name=" + name + "]";}public Set<Contact> getContacts() {return contacts;}public void setContacts(Set<Contact> contacts) {this.contacts = contacts;}public void addContact(Contact contact) {contacts.add(contact);}}
public class Contact {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Contact [id=" + id + ", name=" + name + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Contact other = (Contact) obj;if (id != other.id)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}
在Group的配置文件中配置如下:
<class name="Group" table="t_group"><id name="id"><generator class="increment" /></id><property name="name"></property><set name="contacts"><key column="groupId"/><one-to-many class="Contact" /></set></class>
增加一个<set>标签,里面放的是一对多这个"多"的内容。其中groupId表示的是在"多"的那张表中用来保存group中id的字段,在生成表的时候自动生成这一列。
测试如下:
public void testOne2Many() {Group g = new Group();g.setName("同学");Contact c = new Contact();c.setName("张三");Contact c2 = new Contact();c2.setName("李四");Contact c3 = new Contact();c3.setName("王五");g.addContact(c);g.addContact(c2);g.addContact(c3);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(g); session.save(c);session.save(c2);session.save(c3);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

2. 级联配置

和多对一的级联配置差不多,也是添加配置就可以了。
<set name="contacts" cascade="all"><key column="groupId" /><one-to-many class="Contact" /></set>
测试添加方法:
public void testOne2Many2() {Group g = new Group();g.setName("同学");Contact c = new Contact();c.setName("张三");Contact c2 = new Contact();c2.setName("李四");Contact c3 = new Contact();c3.setName("王五");g.addContact(c);g.addContact(c2);g.addContact(c3);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
测试删除方法:
public void testOne2Many3() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Group g = (Group) session.get(Group.class, 1);session.delete(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
也可以使用离线对象删除数据,那么相关联的字段就会置为空,也就是利用离线对象删除的时候,级联失效。
public void testOne2Many4() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Group g = new Group();g.setId(2);session.delete(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

3. 延迟加载

当配置lazy="false",即不使用懒加载的时候:
public void testOne2Many5() {Group g = null;Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();g = (Group) session.get(Group.class, 2);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}System.out.println(g);}
是可以取到Group的相关信息的。

4. 关联的修改

如果想修改某个Contact对象的group,那么可以使用以下方法来修改:
/** * 关联的修改 *  */public void testOne2Many6() {Group g = null;Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();g = (Group) session.get(Group.class, 2);Contact c = (Contact) session.get(Contact.class, 7);g.getContacts().add(c);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
删除关联:
<span style="white-space:pre"></span>public void testOne2Many7() {<span style="white-space:pre"></span>Group g = null;<span style="white-space:pre"></span>Session session = HibernateUtil.getSession();<span style="white-space:pre"></span>// 创建及开启事务对象<span style="white-space:pre"></span>Transaction trans = null;<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>trans = session.beginTransaction();<span style="white-space:pre"></span>g = (Group) session.get(Group.class, 2);<span style="white-space:pre"></span>Contact c = (Contact) session.get(Contact.class, 7);<span style="white-space:pre"></span>g.getContacts().remove(c);<span style="white-space:pre"></span>trans.commit();<span style="white-space:pre"></span>} catch (HibernateException e) {<span style="white-space:pre"></span>trans.rollback();<span style="white-space:pre"></span>e.printStackTrace();<span style="white-space:pre"></span>} finally {<span style="white-space:pre"></span>HibernateUtil.closeSession(session);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}
注意:这样子操作只会删除关联,相关的关联会置为空,并不是删除数据!
如果想清空整个组的关联直接使用:
// g.getContacts().clear();// g.setContacts(null);

5. extra延迟加载

先看代码:
/** * 一对多一端的集合中的元素个数 *  */public void testOne2Many2() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Group g = (Group) session.get(Group.class, 1);System.out.println(g.getName());System.out.println(g.getName() + "组有" + g.getContacts().size()+ "个联系人");trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
当配置文件中<set>标签内lazy为true的时候发现后台执行的代码是:
Hibernate: select contacts0_.groupId as groupId1_1_, contacts0_.id as id1_, contacts0_.id as id2_0_, contacts0_.name as name2_0_ from t_contact contacts0_ where contacts0_.groupId=?
配置lazy为extra的时候,执行的代码是:
Hibernate: select count(id) from t_contact where groupId =?
可以看出来extra的配置会使的执行起来更聪明有效率。
public void testOne2Many3() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Group g = (Group) session.get(Group.class, 1);System.out.println(g.getName());Contact c = new Contact();c.setId(3);System.out.println(g.getContacts().contains(c));trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
当配置layz="true"时,会查不到这个Contact,配置为extra的时候,可以查到,返回true。

0 0
原创粉丝点击