第三章:Hibernate中的关联映射方案 1)为什么要创建关联映射 当类与类之间建立了关联,就可以方便地从一个类对象导航到另一个与它关联的类对象。 例如order对象,如果想获得与它关联的customer对象,只要调用 Coustomer customer = order.getCustomer() 2):Hibernate中的关联(Association)映射主要有三种 A:一对一 B:一对多 C:多对一 D:多对多 E:每种关联都可以分为单向和双向两种 F:一对一的关联维护在实际项目中使用不多,一对一在Hibernate中可采用主键关联 G:一对多/多对一的关联维护在实际项目中使用是比较多的,在Hibernate中可采用多 种方式来配置一对多的关联,如采用Set、List、Bag、Map等一般采用Set H:多对多的关联维护在实际项目中其实也是比较多的 3)在域模型中,类与类之间最普遍的关系就是关联关系。关联是有方向的。以客户和订单 的关系为例。一个客户能发出多个订单,而一个定单只属于一个客户。从订单到客户是 多对一关联,这意味着每个订单对像都会引用一个客户对像,因此在订单类中应该定义 一个客户的属性,从客户到订单是一对多的关联,这意味着每个客户对像会引用一组 订单对像。因此在客户类中应该定义一个集合类型的属性来引用关联的订单对像。 4)如果仅有从订单到客户的关联,或者仅有从客户到订单的关联称为单向关联。如果同时包 括两种关联,就称为双向关联. 如图: Customer order =============== 1 n ==================== id:long <----------- id:long name:String customer:Customer ============== orderDtm:String ===================== 从Order到Customer的多对一单向关联 Customer order =============== 1 n ==================== id:long -----------> id:long name:String orderDtm:String Orders:Set ===================== =============== 从Customer到Order的一对多单向关联 Customer order =============== 1 n ==================== id:long <-----------> id:long name:String orderDtm:String Orders:Set customer:Customer =============== ===================== 从Customer与Order的一对多双向关联 多对一单向关联关系 A:选择从Order表到Customer的多对一的单向关联,在Order类中需要定义 一个customer属性,而在Customer类中无需定义用于存放Order对像的集 合属性。 B:源代码: public class Customer (Customer类的源码) { private Long id;//代理主键 private String name; public long getId() { return this.id; } private void setId(long id) //把代理主键设置为私有的 { this.id = id; } public Cust(String custname) //构造函数不包含代理主键 { this.custname = custname; } .... } public class Order (Customer类的源码) { private Long id;//代理主键 private String OrderNumber;//订单编号 private Customer customer;//增加一个关联的Customer的属性 .... public long getId() //得到代理主键 { return this.id; } private void setId(long id) //设置代理主键为私有的 { this.id = id; } public Customer getCustomer() { return this.customer; } public void setCustomer(Customer customer) { this.customer=customer; } public Orders(String orderid, Cust cust, String orderdtm) //构造函数 //不包含代理主键 { super(); this.orderid = orderid; this.cust = cust; this.orderdtm = orderdtm; } } C:创建Order表与customer表并创建外键(可选) D:Customer类的所有属性和Customers表中的字段一一对应.而Order类的 customer属性是Customer类型和Orders表中的外键CustomerId对应 Order.hbm.xml文件的配置代码如下: <id name="id" type="long"> <column name="ID" precision="22" scale="0" /> <generator class="sequence"> <param name="sequence">chen_seq</param> </generator> </id> <property name="orderid" type="string"> <column name="ORDERID" length="10" not-null="true" /> </property> <property name="orderdtm" type="string"> <column name="ORDERDTM" length="10" not-null="true" /> </property> <many-to-one name="cust" column="CUSTID" class="ht.oa.hibernate.classes.Cust" lazy="false"/> //此属性千万不能少 name:设置映射的持久化类的属性名 column:持久化类的属性对应表的外键 class:持久化类属性的类型。注意此处一定要用全名,即包含"包名" layz:延迟检索策率 A:true:加载持久化对象时不会调用其他相关的子类对象及外键对象, B:false加载持久化对象的时候就查询相关该对象的所有数据 E:使用代码: ===================================添加一个订单============================== Cust cust=CustDao.get(2);//先查找对应的客户 Orders orders=new Orders("OR4",cust,"2008-2-1");//通过客户实例化订单 OrdersDao.save(orders); //保存订单,保存订单时Hibernate会根据mapping配置文件找到外键,然后进行添加 ========================查询一个客户下的所在订单================================ public static List findByCust(Cust cust) { Session session=SessionManager.newInstance().getSession(); String hql=String.format("from Orders a where a.cust.id=%d",cust.getId()); List orderList=session.createQuery(hql).list(); SessionManager.newInstance().closeSession(); return orderList; } ================查询所有订单的信息资料,以及相关联的Cust的信息=============== 由于Order和Customer之间存在多对一的单向关联关系,因此只要调用 Order. getCustomer()的方法就可以方便从Order对像导航到Customer对像 创建一对多双向关联关系 1)既然是双方关联"一对多双向关联"和"多对一双向关联"是一回事,只不过 "一对多双向关联"听起来更加顺口 2)如果Order对像与Customer对像发生了单向多对一关联,所以如果想获取与它 关联的Customer对像,只要调用 Customer customer=order.getCustomer() 那么对于给定的Customer对像如果想要获取它关联的Order对像,该如何处理 呢?在前面由于Customer对像并不和Order对像关联(因为是单向的)因此必须 通过Hql语句来查询数据库 3)创建步骤: A:先创建Order到Customer多对于关联 需要在Order类中增加一个关于Customer的属性 B:再创建Customer到Order的一对多关联 需要在Customer类中增加一个关于Order的一个集合属性orders C:源代码: public class Customer (Customer类的源码) { private Long id;//代理主键 private String name; private Set orders=new HashSet();//增加一个关于order集合的属性orders public long getId() { return this.id; } private void setId(long id) //把代理主键设置为私有的 { this.id = id; } public Cust(String custname) //构造函数不包含代理主键 { this.custname = custname; } public Set getOrders() { return orders; } public void setOrders(Set orders) { this.orders = orders; } .... } public class Order (Customer类的源码) { private Long id;//代理主键 private String OrderNumber;//订单编号 private Customer customer; //增加一个关联的Customer的属性 .... public long getId() //得到代理主键 { return this.id; } private void setId(long id) //设置代理主键为私有的 { this.id = id; } public Customer getCustomer() { return this.customer; } public void setCustomer(Customer customer) { this.customer=customer; } public Orders(String orderid, Cust cust, String orderdtm) //构造函数 //不包含代理主键 { super(); this.orderid = orderid; this.cust = cust; this.orderdtm = orderdtm; } } D)mapping映射文件 =======================Cust.hbm.xml文件================== 由于CUST表中没有直接与Orders属性对应的字段,因此不能使用<property>元素 来映射,而要使用<set元素> <id name="id" type="long"> <column name="ID" precision="22" scale="0" /> <generator class="sequence"> <param name="sequence">chen_seq</param> </generator> </id> <property name="custname" type="string"> <column name="CUSTNAME" length="10" not-null="true" /> </property> <set name="orders" lazy="false" inverse="true" cascade="all"> //这一句千万不能少 <key column="CUSTID"/> <one-to-many class="ht.oa.hibernate.classes.Orders"/> </set> 说明: name:设置持久化类的属性名。这里为Customer类的orders属性 inverse:控制反转。表示由谁来维护两张表的关系。 A:true:表示由另一方来维护表之间的关系 B:false:表示由自己来维护表之间的的关系。默认为false C:双向关联。必须一方设置为false,而另一方设置为true,也就是说只有一方去 维护两张表之间的关系。这样可以避免产生多余重复的SQL语句甚至致使JDBC 出现异常。相当于老婆与老公都来维护家的关系。老公把地扫了一次,老婆再 去扫一次。做了重复的事件。 D:一般由于外键是在多的一方,所以一般由多的一方去维护两张表之间的关系 也就是说应该在一的方设置为inverse=true; set元素包含两上子元素 key:设定与所关联的持久化类对应的表的外键。此处为CUSTID noe-to-many:中的class指定持久化类的类名 cascade:级联操作.可以取以下几个值: A:save-update:级联更新或插入 B:none:表示不会级联。这是默认值 C:delete:级联删除 Hibernate根据以上配置获取以下信息 1:<set>元素表明Customer类中的orders属性为Set集合类型 2:<class>子元素表明orders集合中存放的对像类型是Order类型 3:<key>子元素表示ORDER表通过外键CUSTID来参照CUSTOMER表 4:cascade表明以后当对Customer表进行操作时,也会级联对ORDER表进行操作 ===============================Order.hbm.xml========================= <id name="id" type="long"> <column name="ID" precision="22" scale="0" /> <generator class="sequence"> <param name="sequence">chen_seq</param> </generator> </id> <property name="orderid" type="string"> <column name="ORDERID" length="10" not-null="true" /> </property> <property name="orderdtm" type="string"> <column name="ORDERDTM" length="10"/> </property> <many-to-one name="cust" column="CUSTID" class="ht.oa.hibernate.classes.Cust" lazy="false" cascade="all"/> =================Order.hbm.xml========================================== E:使用: =================获取一个客户下的所有订单========================= Cust cust=CustDao.get(2);//得到一个客户 Set orders=cust.getOrders();//通过客户得到与之对应的订单对像 Iterator iterator=orders.iterator(); ========================级联删除(删除一个客户时删除他所有的订单)========== 配置Cust.hbm.xml文件的cascde属性: <set inverse="true" name="orders" lazy="false" cascade="delete"> <key column="CUSTID"/> <one-to-many class="ht.oa.hibernate.classes.Orders"/> </set> Cust cust=CustDao.get(1); CustDao.del(cust); =================保存一个订单时把对应的客户也保存================= Cust cust=new Cust("com.cn"); Orders or1=new Orders("OR12",cust,"2005-6-6"); OrdersDao.save(or1); =================保存一个订单时把对应的客户也保存================= 创建一对多双向关联关系总结: 1)在一方创建一个集合,这个集合指向多方 2)在多方创建一个属性,这个属性引用一方 3)配置多方的Xxx.hbm.xml文件时要指定 A:外键列 B:lazy:延迟加载。设置为false C:cascade:级联操作。设置为all。 D:不要设置inverse="true"或设置为inverse="false"表示由多方来控制关联关系 <many-to-one name="cust" column="CUSTID" class="Cust" lazy="false" cascade="all"/> 4)配置一方的Xxx.hbm.xml文件时要指定 A:外键列:<key column> B:lazy:延迟加载。设置为false C:cascade:级联操作。设置为all。 D:inverse="true"。表示由多方来控制 <set name="orders" lazy="false" inverse="true" cascade="all"> <key column="CUSTID"/> <one-to-many class="ht.oa.hibernate.classes.Orders"/> </set>

评论