Hibernate -- 一对多的双向关联关系
示例代码:
Customer.java
package cn.itcast.many2onedouble; import java.util.HashSet; import java.util.Set; /** * 一的一端 */ @SuppressWarnings("serial") public class Customer implements java.io.Serializable { private Integer id; private String name; //一个客户对应多个订单 private Set<Order> orderes=new HashSet<Order>(0); 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 Set<Order> getOrderes() { return orderes; } public void setOrderes(Set<Order> orderes) { this.orderes = orderes; } }
Order.java
package cn.itcast.many2onedouble; /** * 多的一端 */ public class Order { private Integer id; private String orderNumber; private Double price; //建立订单到客户的多一关联 private Customer customer; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getOrderNumber() { return orderNumber; } public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
App.java
package cn.itcast.many2onedouble; import java.util.Iterator; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class App { private static SessionFactory sf=null; static{ Configuration config=new Configuration(); config.configure("cn/itcast/many2onedouble/hibernate.cfg.xml"); config.addClass(Customer.class); config.addClass(Order.class); sf=config.buildSessionFactory(); } //知识点6:保存客户和订单(客户和订单建立双向关联) @Test public void saveCustomerAndOrder(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Customer c=new Customer(); c.setName("关羽"); Order o=new Order(); o.setOrderNumber("NO1"); o.setPrice(12d); //建立订单和客户的双向关联 //建立订单和客户的关联 o.setCustomer(c); //建立客户和订单的关联 c.getOrderes().add(o); //保存客户 session.save(c); //保存订单 session.save(o); tx.commit(); session.close(); } //知识点7:保存客户和不保存订单 @Test public void saveCustomerAndOrderCase(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Customer c=new Customer(); c.setName("飞"); Order o=new Order(); o.setOrderNumber("NO2"); o.setPrice(12d); //建立订单和客户的双向关联 //建立订单和客户的关联 o.setCustomer(c); //建立客户和订单的关联 c.getOrderes().add(o); //保存客户 session.save(c); //保存订单 //session.save(o); tx.commit(); session.close(); } //知识点8:查询客户和订单 @Test public void getCustomer(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //从一的一端开始查询 Customer c=(Customer)session.get(Customer.class, 2); System.out.println(c.getId()+" "+c.getName()); Set<Order> set=c.getOrderes(); Iterator<Order> it=set.iterator(); while(it.hasNext()){ Order o=it.next(); System.out.println(o.getId()+" "+o.getOrderNumber()+" "+o.getPrice()); } tx.commit(); session.close(); } //知识点9:对象导航 @Test public void objectRelation(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Order o1=new Order(); o1.setOrderNumber("NO1"); o1.setPrice(23d); Order o2=new Order(); o2.setOrderNumber("NO2"); o2.setPrice(23d); Order o3=new Order(); o3.setOrderNumber("NO3"); o3.setPrice(23d); Customer c=new Customer(); c.setName("关羽"); //order1关联到customer 而customer没有关联到order1 --单向关联 o1.setCustomer(c); //customer关联到order2 order3 而order2 order3 没有关联到customer 单向关联 c.getOrderes().add(o2); c.getOrderes().add(o3); //保存o1 session.save(o1); //保存c //session.save(c); //保存o2 //session.save(o2); tx.commit(); session.close(); } /* * 知识点10:保持程序的健壮性 */ @Test public void testDouleRaletion(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Customer c=new Customer(); c.setName("飞"); Order o=new Order(); o.setOrderNumber("NO2"); o.setPrice(12d); /************************************************************************************************************/ //建立订单和客户的双向关联 //建立订单和客户的关联 o.setCustomer(c); //建立客户和订单的关联 c.getOrderes().add(o); /************************************************************************************************************/ //保存客户 session.save(c); //保存订单 session.save(o); tx.commit(); session.close(); } /************************************************************************************************************/ //知识点11:订单变更客户 //更改订单表id=6的customer_id=3更改为4 @Test public void changeOrderHander(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //获取id=6号的订单,查询的订单和订单关联的客户放置在sessioln的一级缓存中,同时还产生一份快照 Order o6=(Order)session.get(Order.class, 6); //获取id=4客户 Customer c4=(Customer)session.get(Customer.class, 4); /**************************************************************************************/ //建立关联关系 /* * 在set标签中配置inverse="true",则多的一端说了算,一的一端说了不算 * 当缓存中的数据发生变化时 * * 如果多的一端关联的客户发生变化,此时执行update语句 * * 如果一的一端对应的订单集合中的订单发生变化时, * 因为一的一端说了不算,所以不会按照订单集合中订单的变化执行update语句 */ //让6号订单和4号客户关联 o6.setCustomer(c4); //有update语句 //在4号客户对应的订单集合中加入6号订单 c4.getOrderes().add(o6); //没有update语句,加和不加没有影响,但建议还是加上 /**************************************************************************************/ tx.commit(); session.close(); } /* * 知识点12:解除关联关系 * 解除6号订单和3号客户的关联 */ @Test public void removeRelation(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //获取id=6号的订单,查询的订单和订单关联的客户放置在sessioln的一级缓存中,同时还产生一份快照 Order o6=(Order)session.get(Order.class, 6); //获取id=3客户 Customer c3=(Customer)session.get(Customer.class, 3); //解除双方的关联关系 o6.setCustomer(null); c3.getOrderes().remove(o6); tx.commit(); session.close(); } /* * 知识点13:级联删除删除1号客户的同时,删除1号客户所关联的订单 */ @Test public void deleteCustomerCaseOrder(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //获取id=1客户 Customer c1=(Customer)session.get(Customer.class, 1); session.delete(c1); tx.commit(); session.close(); } /* * 知识点14:解除关联关系 ---父子关系 * 解除6号订单和3号客户的关联,同时删除6号订单 */ @Test public void deleteOrderOrphan(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); //获取id=6订单 Order o6=(Order)session.get(Order.class, 6); //获取id=3客户 Customer c3=(Customer)session.get(Customer.class, 3); //解除关联关系 o6.setCustomer(null); c3.getOrderes().remove(o6); tx.commit(); session.close(); } }
Customer.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"> <hibernate-mapping> <class name="cn.itcast.many2onedouble.Customer" table="customers"> <id name="id" type="integer"> <column name="id"/> <generator class="increment"/> </id> <property name="name" type="string"> <column name="name"/> </property> <!-- 配置set集合 set:使用set标签配置客户对应的订单集合 table:订单集合中的订单对应的表,可以不加 cascade="save-update":级联保存和更新:当保存customer对象时,同时要保存customer对象所关联的订单集合orderes集合 "delete":级联删除 inverse="true":表示多的一端(Order端)为主控方法(谁是主控方,谁就说算,多的一端说了算) (全国人民) 一的一端(Customer端)不是主控方法 (国家主席) --> <set name="orderes" table="orders" cascade="delete-orphan" inverse="true"> <key> <!-- 对应的是orders表的外键,可以理解为, orderes集合中的订单对象是通过orders表的外键customer_id查询出来的 select * from orders where cutomer_id=客户id 结构是多条记录 --> <column name="customer_id"/> </key> <!-- one-to-many:表示一对多,class表示集合中存放的对象是Order对象 --> <one-to-many class="cn.itcast.many2onedouble.Order"/> </set> </class> </hibernate-mapping>
Order.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"> <hibernate-mapping> <class name="cn.itcast.many2onedouble.Order" table="orders"> <id name="id" type="integer"> <column name="id"/> <generator class="increment"/> </id> <property name="orderNumber" type="string"> <column name="orderNumber"/> </property> <property name="price" type="double"> <column name="price"/> </property> <!-- customer要获取的是Customer对象, 该Customer对象通过orders表的外键customer_id来查询customers表 select * from customes where id=customer_id many-to-one:使用该标签来映射多对一关联: name:映射的持久化类中的属性 class:映射的持久化类中的属性的类型 cascade="save-update":级联保存和更新 * 就是将order对象所关联的临时对象Customer变成持久对象(就在session的一级缓存中,就能插入到数据库中) --> <many-to-one name="customer" class="cn.itcast.many2onedouble.Customer" cascade="save-update"> <!-- 映射的表中的列 --> <column name="customer_id"/> </many-to-one> </class> </hibernate-mapping>
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property> <!-- 配置数据库的方言,让hibernate知道连接的是哪个数据库--> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 配置利用javaBean和映射文件生成数据库中的表 hibernate.hbm2ddl.auto值 * create:执行时,先查找该表是否存在,如存在先删除表,在创建表 * none:不能创建表,只能往表中插入数据,如表不存在抛出异常,默认值 * update:执行时, 情况一: 先查找该表是否存在,如果表存在,直接插入,如果表不存在,先创建表,再插入数据. 情况二: 先查找该表是否存在,如果表存在,但表的结构不一样,要修改表的结构 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 显示hibernate生成的sql语句 --> <property name="hibernate.show_sql">true</property> <!-- 显示格式化得sql语句 --> <property name="hibernate.format_sql">false</property> </session-factory> </hibernate-configuration>