(当然双向1-n与双向n-1是完全相同的。)
双向1-n需要在1的一端访问n的一端,同时,n的一端也可以访问1的一端。
举例:Customer-Order
一、代码演示:
{类文件↓}
Customer:
1 import java.util.HashSet; 2 import java.util.Set; 3 4 public class Customer { 5 6 private Integer customerId; 7 private String customerName; 8 9 10 /** 11 * 1. 此处的集合类型必须要用 接口类型,后面会发现读取orders 的类型是org.hibernate.collection.internal.PersistentSet 12 * 一个hibernate内置的一个集合类,是set的子类 13 * 2. 此处需要将集合进行初始化,防止空指针异常 14 */ 15 private Set<Order> orders = new HashSet<>(); 16 17 18 public Set<Order> getOrders() { 19 return orders; 20 } 21 public void setOrders(Set<Order> orders) { 22 this.orders = orders; 23 } 24 25 26 public Integer getCustomerId() { 27 return customerId; 28 } 29 public void setCustomerId(Integer customerId) { 30 this.customerId = customerId; 31 } 32 public String getCustomerName() { 33 return customerName; 34 } 35 public void setCustomerName(String customerName) { 36 this.customerName = customerName; 37 } 38 39 }
Customer.class
Order:
1 public class Order { 2 3 private Integer orderId; 4 private String orderName; 5 6 private Customer customer; 7 8 public Integer getOrderId() { 9 return orderId; 10 } 11 12 public void setOrderId(Integer orderId) { 13 this.orderId = orderId; 14 } 15 16 public String getOrderName() { 17 return orderName; 18 } 19 20 public void setOrderName(String orderName) { 21 this.orderName = orderName; 22 } 23 24 public Customer getCustomer() { 25 return customer; 26 } 27 28 public void setCustomer(Customer customer) { 29 this.customer = customer; 30 } 31 32 }
Order.class
{映射文件↓}
hbm.xml配置文件中,并没有相应的<one-to-many>属性,而是用<set>来代替,而<set>的子元素中,有<one-to-many>子元素
Customer.hbm.xml:
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2015-11-29 10:18:07 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping package="com.zit.hibernate.n21.both"> 6 <class name="Customer" table="CUSTOMERS"> 7 <id name="customerId" type="java.lang.Integer"> 8 <column name="CUSTOMER_ID" /> 9 <generator class="native" /> 10 </id> 11 <property name="customerName" type="java.lang.String"> 12 <column name="CUSTOMER_NAME" /> 13 </property> 14 15 <!-- 映射1 对多的那个集合属性 --> 16 <set name="orders" table="ORDERS" inverse="true" cascade="delete"> 17 <key column="CUSTOMER_ID"></key> 18 <one-to-many class="Order"/> 19 </set> 20 21 </class> 22 </hibernate-mapping>
Customer.hbm.xml
注意:
1 <set name="orders" table="ORDERS" inverse="true" cascade="delete"> 2 <key column="CUSTOMER_ID"></key> 3 <one-to-many class="Order"/> 4 </set>
<set> name是1的一端的包含的n的一端的属性名;table=“”是表名,参照的是ORDERS表,得跟Orders.hbm.xml中的那个表名一致。
<key> 子元素中的column=“”要与 Orders.hbm.xml 中的 <many-to-one>中的<column/>对应一致。
(务必注意这两个一一对应关系)
<one-to-many> 对应n的一端的类全类名。要指明是one-to-many类型,因为many-to-many也是用set来表示的。
Order.hbm.xml
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2015-11-29 10:18:07 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping package="com.zit.hibernate.n21.both"> 6 <class name="Order" table="ORDERS"> 7 <id name="orderId" type="java.lang.Integer"> 8 <column name="ORDER_ID" /> 9 <generator class="native" /> 10 </id> 11 <property name="orderName" type="java.lang.String"> 12 <column name="ORDER_NAME" /> 13 </property> 14 <many-to-one name="customer" class="Customer"> 15 <column name="CUSTOMER_ID" /> 16 </many-to-one> 17 </class> 18 </hibernate-mapping>
Order.hbm.xml
二、使用注意:
1.插入数据时:
先保存1的一端的数据,再保存多的一端的数据,若反之,则会多出UPDATE语句。(此处会多出的UPDATE是在单向n- 1中,会多的UPDATE语句数量的两倍,因为双向1-n两边都会维护关联关系)
但是这种双向关联,在插入时,会有UPDATE语句产生,这与单向的n-1不同,在单向的n-1关联关系中,若用户先插入1的一端,再插入n的一端,是不会出现UPDATE语句的。在双向1-n关联关系中,若先插入1的一端,再插入多的一端,UPDATE会相应少,数目为插入的多的一端的数据数目。反之,若先插入n的一端,再插入1的一端,则UPDATE语句数目会是前者的两倍。
[双方都维护关联关系,会降低程序效率。可以通过设置 inverse 属性来决定是由双向关联中的哪一方来维护表和表之间的关联关系。inverse = false 的为主动方,inverse=true的为被动方。若未设置inverse=true,则双方都维护。
在1-n关系中,将n方设置为主控方将有助于性能改善,见Customer.hbm.xml中的设置]
session.save(object);
2.在Customer.class中,需要将set<Order>进行初始化,即:
Set<Order> orders = new HashSet<>();
否则会出现空指针异常。
3.延迟加载:
在获取了Customer的对象后,customer.getOrders().getClass()返回的是一个hibernate内置的
集合类型:PersistentSet,该类型具有延迟加载和存放代理对象的功能。是Java.Util.Set接口的一个实现类。
这也表明了在声明定义几何属性时必须把属性声明为Java接口类型,如Set,而不能是HashSet
4.懒加载异常:LazyInitializationException
5.在需要使用集合中元素的时候才进行初始化,而使用集合的size()的时候都不会进行初始化。
6.<set>中配置 order-by,让集合内的元素按指定的属性,升序、降序排列,
例:<set order-by="ORDER_NAME DESC">
注意:这里使用的是表中的字段名,而不是持久化类的属性名。