hibernate基础(五)--一对多关联映射
2018-01-18 14:39
387 查看
Hibernate的一对多关联映射
以客户和联系人为例客户实体
package cn.imau.entity; import java.util.HashSet; import java.util.Set; public class Customer { private Long cust_id; private String cust_name; private String cust_source; private String cust_industry; private String cust_level; private String cust_phone; private String cust_mobile; //一个客户有多个联系人:客户中应该放联系人的集合 private Set<LinkMan> linkMens=new HashSet<LinkMan>(); public Long getCust_id() { return cust_id; } public void setCust_id(Long cust_id) { this.cust_id = cust_id; } public String getCust_name() { return cust_name; } public void setCust_name(String cust_name) { this.cust_name = cust_name; } public String getCust_source() { return cust_source; } public void setCust_source(String cust_source) { this.cust_source = cust_source; } public String getCust_industry() { return cust_industry; } public void setCust_industry(String cust_industry) { this.cust_industry = cust_industry; } public String getCust_level() { return cust_level; } public void setCust_level(String cust_level) { this.cust_level = cust_level; } public String getCust_phone() { return cust_phone; } public void setCust_phone(String cust_phone) { this.cust_phone = cust_phone; } public String getCust_mobile() { return cust_mobile; } public void setCust_mobile(String cust_mobile) { this.cust_mobile = cust_mobile; } public Set<LinkMan> getLinkMens() { return linkMens; } public void setLinkMens(Set<LinkMan> linkMens) { this.linkMens = linkMens; } }
联系人实体
package cn.imau.entity; public class LinkMan { private Long lkm_id; private String lkm_name; private String lkm_gender; private String lkm_phone; private String lkm_mobile; private String lkm_email; private String lkm_qq; private String lkm_position; private String lkm_memo; private Customer customer; public Long getLkm_id() { return lkm_id; } public void setLkm_id(Long lkm_id) { this.lkm_id = lkm_id; } public String getLkm_name() { return lkm_name; } public void setLkm_name(String lkm_name) { this.lkm_name = lkm_name; } public String getLkm_gender() { return lkm_gender; } public void setLkm_gender(String lkm_gender) { this.lkm_gender = lkm_gender; } public String getLkm_phone() { return lkm_phone; } public void setLkm_phone(String lkm_phone) { this.lkm_phone = lkm_phone; } public String getLkm_mobile() { return lkm_mobile; } public void setLkm_mobile(String lkm_mobile) { this.lkm_mobile = lkm_mobile; } public String getLkm_email() { return lkm_email; } public void setLkm_email(String lkm_email) { this.lkm_email = lkm_email; } public String getLkm_qq() { return lkm_qq; } public void setLkm_qq(String lkm_qq) { this.lkm_qq = lkm_qq; } public String getLkm_position() { return lkm_position; } public void setLkm_position(String lkm_position) { this.lkm_position = lkm_position; } public String getLkm_memo() { return lkm_memo; } public void setLkm_memo(String lkm_memo) { this.lkm_memo = lkm_memo; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
客户映射
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.imau.entity" > <class name="Customer" table="cst_customer" > <id name="cust_id" > <generator class="native"></generator> </id> <property name="cust_name" column="cust_name" ></property> <property name="cust_source" column="cust_source" ></property> <property name="cust_industry" column="cust_industry" ></property> <property name="cust_level" column="cust_level" ></property> <property name="cust_phone" column="cust_phone" ></property> <property name="cust_mobile" column="cust_mobile" ></property> <!-- 集合,一对多关系,在配置文件中配置 --> <!-- name属性:集合属性名 column属性: 外键列名 class属性: 与我关联的对象完整类名 --> <!-- 级联操作: cascade save-update: 级联保存更新 delete:级联删除 all:save-update+delete 级联操作: 简化操作.目的就是为了少些两行代码. --> <!-- inverse属性: 配置关系是否维护. true: customer不维护关系 false(默认值): customer维护关系 inverse属性: 性能优化.提高关系维护的性能. 原则: 无论怎么放弃,总有一方必须要维护关系. 一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃. --> <set name="linkMens"> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set> </class> </hibernate-mapping>
联系人映射
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.imau.entity" > <class name="LinkMan" table="cst_linkman" > <id name="lkm_id" > <generator class="native"></generator> </id> <property name="lkm_gender" ></property> <property name="lkm_name" ></property> <property name="lkm_phone" ></property> <property name="lkm_email" ></property> <property name="lkm_qq" ></property> <property name="lkm_mobile" ></property> <property name="lkm_memo" ></property> <property name="lkm_position" ></property> <!-- 多对一 --> <!-- name属性:引用属性名 column属性: 外键列名 class属性: 与我关联的对象完整类名 --> <!-- 级联操作: cascade save-update: 级联保存更新 delete:级联删除 all:save-update+delete 级联操作: 简化操作.目的就是为了少些两行代码. --> <!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方. --> <many-to-one name="customer" column="lkm_cust_id" class="Customer" > </many-to-one> </class> </hibernate-mapping>
将映射添加到配置文件
<!-- 将Session与线程绑定=>--> <property name="hibernate.current_session_context_class">thread</property> <mapping resource="cn/imau/entity/Customer.hbm.xml" /> <mapping resource="cn/imau/entity/LinkMan.hbm.xml" />
HibernateUtils
package cn.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtils { private static SessionFactory sf; static{ //1 创建,调用空参构造 Configuration conf = new Configuration().configure(); //2 根据配置信息,创建 SessionFactory对象 sf = conf.buildSessionFactory(); } //获得session => 获得全新session public static Session openSession(){ //3 获得session Session session = sf.openSession(); return session; } //获得session => 获得与线程绑定的session public static Session getCurrentSession(){ //3 获得session Session session = sf.getCurrentSession(); return session; } public static void main(String[] args) { System.out.println(HibernateUtils.openSession()); } }
编写测试代码
package cn.imau.test; import cn.imau.entity.Customer; import cn.imau.entity.LinkMan; import cn.utils.HibernateUtils; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; public class test { @Test //保存一个客户两个联系人 public void demo1(){ Session session= HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //创建一个客户 Customer customer=new Customer(); customer.setCust_name(" Manager Wang"); //创建两个联系人 LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("secretary Li"); LinkMan linkMan2=new LinkMan(); linkMan2.setLkm_name("assistant Zhang"); //建立关系 customer.getLinkMens().add(linkMan1); customer.getLinkMens().add(linkMan2); linkMan1.setCustomer(customer); linkMan2.setCustomer(customer); session.save(customer); session.save(linkMan1); session.save(linkMan2); transaction.commit(); } }
控制台输出结果
查询数据库
从上图的查询结果可以看出,数据表创建成功,并插入了相应的数据。从上面代码可以发现我们建立的关系是双向的,即客户关联了联系人,同时联系人也关联了客户。下面
我们测试一下只保存客户或者只保存联系人。
@Test //保存操作只保存一方是否可以? public void demo2(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //创建一个客户 Customer customer=new Customer(); customer.setCust_name("Manager li"); //创建联系人 LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("assistant Zhao"); //建立关系 customer.getLinkMens().add(linkMan1); linkMan1.setCustomer(customer); session.save(customer);//瞬时对象异常,持久态的对象关联了一个瞬时态对象的异常 //session.save(linkMan1); transaction.commit(); }
执行这段代码,会出现以下错误
一对多的相关操作
级联操作是指当主控方执行保存、更新或删除操作时,其关联对象(被控方)也执行相同的操作。在映射文件中通过cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。级联保存或更新
级联是有方向性的,所谓的方向性指的是,在保存一的一方级联多的一方和在保存多的一方级联一的一方。保存客户级联联系人
在客户的映射文件进行如下配置
<set name="linkMens" cascade="save-update"> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set>
编写测试代码
@Test //级联保存:只保存一边的问题 //级联是有方向性的,保存客户同时级联客户的联系人 //在Customer.hbm.xml中的<set>标签上配置cascade="save-update" public void demo3(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //创建一个客户 Customer customer=new Customer(); customer.setCust_name("Manager liu"); //创建联系人 LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("assistant Zhao"); //建立关系 customer.getLinkMens().add(linkMan1); linkMan1.setCustomer(customer); session.save(customer); transaction.commit(); }
执行代码
保存联系人级联客户
在联系人映射文件中进行如下配置
<many-to-one cascade="save-update" name="customer" column="lkm_cust_id" class="Customer" > </many-to-one>
编写测试代码
@Test //级联保存:只保存一边的问题 //级联是有方向性的,保存联系人同时级联客户 //在LinkMan.hbm.xml中的<many-to-one>标签上配置cascade="save-update" public void demo4(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //创建一个客户 Customer customer=new Customer(); customer.setCust_name("Manager guo"); //创建联系人 LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("assistant hao"); //建立关系 customer.getLinkMens().add(linkMan1); linkMan1.setCustomer(customer); session.save(linkMan1); transaction.commit(); }
执行代码
测试对象的导航的问题
我们所说的对象导航其实就是在维护双方的关系。customer.getLinkMens().add(linkMan1); linkMan1.setCustomer(customer);
我们在客户和联系人端都配置了
cascade="save-update",会产生什么样的效果呢?
@Test //测试对象导航和级联操作 public void demo5(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //创建一个客户 Customer customer=new Customer(); customer.setCust_name("Manager lu"); //创建三个联系人 LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("assistant jiang"); LinkMan linkMan2=new LinkMan(); linkMan2.setLkm_name("secretary guo"); LinkMan linkMan3=new LinkMan(); linkMan1.setLkm_name("assistant zhu"); //建立关系 linkMan1.setCustomer(customer); customer.getLinkMens().add(linkMan2); customer.getLinkMens().add(linkMan3); //条件是双方都配置了cascade="save-update" session.save(linkMan1);//数据库中有几条记录?发送几条insert语句? 4条 //session.save(customer);//发送几条insert语句? 3条 //session.save(linkMan2);//发送几条insert语句? 1条 transaction.commit(); }
级联删除
@Test //删除有关联的对象:(默认情况:Hibernate先将关联对象的外键置为NULL,删除客户对象) public void demo6(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); Customer customer=session.get(Customer.class,1L); session.delete(customer); transaction.commit(); }
运行代码
删除客户的时候同时删除客户的联系人
在客户映射文件中配置
<set name="linkMens" cascade="delete,save-update"> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set>
编写测试代码
@Test //级联删除:级联删除有方向性 //删除客户同时级联删除联系人 //在Customer.hbm.xml中的<set>标签上配置cascade="delete" public void demo7(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //级联删除:必须是先查询再删除的 //因为查询到客户,这时候客户的联系人集合中就会有数据 Customer customer=session.get(Customer.class,4L); session.delete(customer); transaction.commit(); }
删除联系人的同时删除客户
在联系人映射文件中配置
<many-to-one cascade="delete,save-update" name="customer" column="lkm_cust_id" class="Customer" > </many-to-one>
编写测试代码
@Test //级联删除:级联删除有方向性 //删除联系人同时级联删除客户 //在LinkMan.hbm.xml中的<many-to-one>标签上配置cascade="delete" public void demo8(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); //级联删除:必须是先查询再删除的 LinkMan linkMan=session.get(LinkMan.class,4L); session.delete(linkMan); transaction.commit(); }
双向关联产生多余的sql语句
就是让一的一方放弃外键的维护权<set name="linkMens" cascade="delete,save-update" inverse="true"> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set>
inverse的默认值是false,代表不放弃外键维护权,配置值为true,代表放弃了外键的维护权。
区分cascade和inverse
@Test //cascade和inverse //cascade强调的是操作一个对象的时候,是否操作其关联对象 //inverse强调的时外键的维护权 public void demo9(){ Session session=HibernateUtils.getCurrentSession(); Transaction transaction=session.beginTransaction(); Customer customer=new Customer(); customer.setCust_name("Manager Du"); LinkMan linkMan1=new LinkMan(); linkMan1.setLkm_name("assistant bu"); //在Customer.hbm.xml中的<set>标签上配置cascade="save-update" inverse="true" customer.getLinkMens().add(linkMan1); session.save(customer); transaction.commit(); }
相关文章推荐
- Hibernate基础 ( 4 )单向关联映射
- Hibernate基础之基本映射与关联映射
- hibernate基础(六)--多对多关联映射
- Hibernate的关联映射---6.1.6: 双向n-n关联
- Hibernate关联映射 --- 多对多实例分析(单向关联)
- Hibernate数据关联映射之一对一和多对多
- Hibernate关联映射--一对多映射
- Hibernate高级实体关联映射之多值的实体关联(一对多关联,使用bag)
- hibernate映射文件基础
- Hibernate读书笔记-----Hibernate的关联映射之N-N关联映射 .
- Hibernate一对多关联映射
- 【Hibernate】一对一唯一外键关联映射
- Hibernate高级实体关联映射之多值的实体关联(用组件类实现三重关联,单向导航)
- Hibernate教程04_关系映射之一对一单向外键关联
- Hibernate关联映射属性介绍
- hibernate多对一关联只映射出一张表
- Hibernate 、继承关联映射
- 在测试Hibernate的一对多双向关联映射时
- Hibernate之一对多关联映射
- 【Hibernate】从入门到精通(六)关联映射之多对一映射