Hibernate:一对多双向关联关系
前言:最近做表间关联,发现有点混乱。所以就做一下归纳。主要讲Hibernate的一对多双向关联关系。类与类之间到底是建立单向关联,还是双向关联,这是由业务需求决定的。
笔者获取到的经验之谈:Hibernate使用增、删、改比较好。查询还是有本地SQL比较方便。
一、先讲:多对一的单向关联关系
在类与类之间各种各样的关系中,要算多对一的单向关联关系和关系数据库中的外键参照关系最匹配了。在Orders类中需要放一个customer属性,而在Customer类中无需定义用于存放Orders对象的集合属性。
下面以Customer与Orders为例。(Oracle、Hibernate采用hibernate.properties配置文件)
1、 Orders的表结构。
- -- Create table
- create table ORDERS
- (
- orderid NUMBER not null,
- customerid NUMBER,
- address VARCHAR2(1000)
- );
并设置orderid为主键。
2、 Orders的java程序。
- public class Orders {
- private int orderId;
- private Customer customerId;
- private String address;
- //……开setter和getter。
- }
3、 Orders的对象-关系映射文件Orders.hbm.xml。
- <class name="edu.hibernateOneToMany.domain.Orders"table="ORDERS" schema="scott">
- <id name="orderId" column="ORDERID"type="java.lang.Integer">
- <generator class="sequence">
- <paramname="sequence">SQ_ORDERS</param>
- </generator>
- </id>
- <many-to-one name="customerId" column="CUSTOMERID"class="edu.hibernateOneToMany.domain.Customer" not-null="true" />
- <property name="address"type="java.lang.String" >
- <column name="ADDRESS"/>
- </property>
- </class>
重点说明:
<mang-to-one>元素建立了customerId属性和ORDERS表的外键CUSTOMERID之间的映射。她包括以下属性。
(1) name:设定待映射的持久化类的属性名,此外为Orders类的customerId属性。
(2) column:设定和持久化类的属性对应的表的外键,此外为ORDERS表的外键CUSTOMERID。
(3) class:设定持久化化类的属性的类型,此处设定customerId属性为Customer类型。
(4) not-null:如果为true,表示customerId属性不允许为null,该属性的默认值为false。
not-null属性会影响hbm2ddl工具生成的数据库Schema,hbm2ddl工具会为OREDERS表的CUSTOMERID外键设置not null约束,但not-null属性不会影响hbm2java工具生成的Java源代码。此外,not-null属性还会影响Hibernate的运行时行为,Hibernate在保存Orders对象时,会先检查它的customer属性是否为null。
提示:是否应该把<mang-to-one>的not-null属性设为true,这是由事迹业务需求决定的。
二、再讲:一对多的双向关联关系
继续上面已经讲到的多对一,这里再讲一对多即可。
1、 Customer表结构。
- -- Create table
- create table CUSTOMER
- (
- customerid NUMBER not null,
- custmername VARCHAR2(100)
- );
并设置customerid为主键。
2、 Customer的java程序。
需要在Customer类中增加一个集合类型的orders属性。
- public class Customer {
- private intcustomerId;
- private StringcustomerName;
- private Set orders=newHashSet();//作为外键
- //……开setter和getter。
- }
3、 重点说明:
(1) Hiber要求在持久化类中定义集合类属性是,必须把属性声明为借口类型,如java.util.Set、java.util.Map和java.util.List。声明为借口可以提高持久化类的透明性,当Hibernate调用setOrders(Set orders)方法时,传递的参数是Hibernate自定义的实现该借口的类的实例。如果把orders声明为java.util.HashSet类型(踏实java.util.Set借口的一个实现类),就强迫Hibernate只能把HashSet类的实例传给setOrders()方法。
(2) 例如
privateSet orders = new HashSet();
这样可以提高程序的健壮性,避免应用程序访问取值为null的orders集合而抛出的NullPointerException,例如以下程序访问Customer对象的orders集合,即使orders集合中不包含任何元素,但是调用orders.iterator()方法不会抛出NullPointerException异常,因为集合并不会为null。
Setorders = customer. getOrders();
Iteratorit = orders.iterator();
While(it.hashNext()){
……
}
4、 Customer的对象-关系映射文件Customer.hbm.xml。
- <classname="edu.hibernateOneToMany.domain.Customer"table="CUSTOMER" schema="scott">
- <id name="customerId"column="CUSTOMERID" type="java.lang.Integer">
- <generator class="sequence">
- <paramname="sequence">SQ_COSTOMER</param>
- </generator>
- </id>
- <property name="customerName"type="java.lang.String" >
- <column name="CUSTMERNAME"/>
- </property>
- <setname="orders" cascade="save-update"inverse="true">
- <keycolumn="CUSTOMERID" />
- <one-to-many class="edu.hibernateOneToMany.domain.Orders" />
- </set>
- </class>
重点说明:
建立关联的set元素。
<set>元素包括以下属性。
(1) name:设定特殊映射的持久化类的属性名,这里为Customer类的orders属性。
(2) cascade:当取值为”sava-update“,表示级联保存和更新。
(3) inverse:表示双向关联中,这端为镜像。
<set>元素还包含两个子元素:<key>和<one-to-many>。<one-to-many>元素设定所关联的持久化类,此处为Orders类,<key>元素设定与所关联的持久化类对应的表的外键,此处为ORDERS表的CUSTOMERID字段。
三、测试。
简单说明:本演示实在java工程下完成的,采用oracle数据库,hibernate采用hibernate.properties作为配置文件。
示例代码
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import org.hibernate.Session;
- import edu.hibernateOneToMany.domain.Customer;
- import edu.hibernateOneToMany.domain.Orders;
- public class CustomerDaoTest {
- static SessionFactorysessionFactory;
- static{
- Configurationconfiguration = new Configuration();
- configuration.addClass(Customer.class);
- configuration.addClass(Orders.class);
- sessionFactory= configuration.buildSessionFactory();
- }
- public static voidmain(String[] args) {
- Session session= sessionFactory.openSession();
- Transactiontransaction= session.beginTransaction();
- // 步骤一 获取一个用户。
- Customercustomer = (Customer) session.load(Customer.class, 2);
- // 步骤二 创建一张订单。
- Orders orders =new Orders();
- orders.setAddress("河北省海港区东秦");
- orders.setCustomerId(customer);
- // 步骤三 向用户属性中加入一张订单。
- customer.getOrders().add(orders);
- // 步骤四 用户更新属性。(hibernate会自动向客户的orders中插入一条记录)
- session.update(customer);
- transaction.commit();
- session.close();
- }
- }
重点说明
这里我设置客户已经存在,用面向对象的思想去理解。只有顾客存在了,才有订单存在的意义。大体分为四步。当然这里仅仅是最简单的增加,其他的操作类似。
如有好的建议,可留言或发至笔者邮箱:fzb_xxzy@163.com