Hibernate的一对多和多对一操作是非常方便的,如果在减少数据库复杂度的原则来说,把一些逻辑处理放在持久层,还是一个比较常见的方法。
Hibernate的一对多和多对一操作真的很方便,如果系统采用Hibernate作为持久层,完全可以把对应的一对多和多对一逻辑关系放在Hibernate里面控制,减少数据库的负担,而且也更清晰。
1、多对一和一对多概念
其实这个概念上来说很简单,比如一个客户可以有多个订单,多个订单属于同一个客户。就是最基本的一对多,和多对一。数据库使用中,感觉多对一和一对多算是比较常见的逻辑关系了。
我曾经做过一些数据库,比如某些政府部门的,其表单很设计的很简单粗糙,甚至连主键都没有,完全靠在事务层补全这些关系。其实通过Hibernate持久层来实现逻辑关系也是很不错的方法。下面的例子,就是数据库逻辑上基本没有定义,主要放在持久层里面。这个也主要是我对数据库操作属于半通水的原因。
2、数据库层
这里面有两个表单,一个CUSTOMER,客户表单,一个是ORDERS,订单表单。生成客户表单,这个是在SQLServer里面做的,其实其他都一样,因为逻辑关系在Hibernate上面,id是主键非空,其他可以为空:
1. CREATETABLE[dbo].[CUSTOMER](
2. [id][numeric](18,0)NOTNULL,
3. [name][varchar](50)NULL,
4. [age][int]NULL,
5. CONSTRAINT[PK_CUSTOMER]PRIMARYKEY)
订单表单
id为主键非空,CUSTOMER_id是对应客户主键,也非空,这里不做外键设置。
6. CREATETABLE[dbo].[ORDERS](
7. [id][numeric](18,0)NULLPRIMARYKEY,
8. [CUSTOMER_id][numeric](18,0)NOTNULL,
9. [ORDER_NUMBER][varchar](50)NULL,
10. [PRICE][numeric](18,3)NULL
11. )
3、Hibernate设定
HIbernate里面,一对多的对象体现,是客户有一个集合set,set里面放着对应订单,而多对一体现,是订单里面有一个CUSTOMER对象,表明该订单所属的客户。其中,CUSTOMER类为:
12. publicclassCustomerimplementsjava.io.Serializable{
13. privateLongid;
14. privateStringname;
15. privateIntegerage;
16. privateSetrderses=newHashSet();
17.
18. }
后面的getXXX和setXXX方法就省去了,同样订单类就是:
19. publicclassOrdersimplementsjava.io.Serializable{
20. privateLongid;
21. privateCustomercustomer;
22. privateStringorderNumber;
23. privateDoubleprice;
24.
25. }
而对应hbm文档,就是map文档如下:
26. CUSTOMER.hbm.xml
27. <!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
28. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
29. <!--
30. MappingfileautogeneratedbyMyEclipsePersistenceTools
31. -->
32. <hibernate-mapping>
33. <classnameclassname="onetomany.Customer"table="CUSTOMER"schema="dbo"catalog="DBTEST">
34. <idnameidname="id"type="java.lang.Long">
35. <columnnamecolumnname="id"precision="18"scale="0"/>
36. <generatorclassgeneratorclass="increment"/>
37. </id>
38. <propertynamepropertyname="name"type="java.lang.String">
39. <columnnamecolumnname="name"length="50"/>
40. </property>
41. <propertynamepropertyname="age"type="java.lang.Integer">
42. <columnnamecolumnname="age"/>
43. </property>
44. <setnamesetname="orderses"inverse="true"lazy="true"cascade="all">
45. <key>
46. <columnnamecolumnname="CUSTOMER_id"precision="18"scale="0"not-null="true"/>
47. </key>
48. <one-to-manyclassone-to-manyclass="onetomany.Orders"/>
49. </set>
50. </class>
51. </hibernate-mapping>
这个里面,其他都很简答了,其中<generatorclass="increment"/>表示主键值自动增加,这个主要针对字符串对应的,主要体现多对以的是:
1. <setnamesetname="orderses"inverse="true"lazy="true"cascade="all">
2. <key>
3. <columnnamecolumnname="CUSTOMER_id"precision="18"scale="0"not-null="true"/>
4. </key>
5. <one-to-manyclassone-to-manyclass="onetomany.Orders"/>
6. </set>
其中,set表示,对应集合;fetch和lazy主要是用来级联查询的,而cascade和inverse主要是用来级联插入和修改的,这几个主要包括对集合的控制。<one-to-manyclass="onetomany.Orders"/>表示对应类,即set里面包含的类,而key主要是用于确定set里面对应表单列。
7. ORDERS的hbm
8. <?xmlversionxmlversion="1.0"encoding="utf-8"?>
9. <!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
10. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
11. <!--
12. MappingfileautogeneratedbyMyEclipsePersistenceTools
13. -->
14. <hibernate-mapping>
15. <classcatalogclasscatalog="DBTEST"name="onetomany.Orders"schema="dbo"table="ORDERS">
16. <idnameidname="id"type="java.lang.Long">
17. <columnnamecolumnname="id"precision="18"scale="0"/>
18. <generatorclassgeneratorclass="increment"/>
19. </id>
20. <many-to-oneclassmany-to-oneclass="onetomany.Customer"fetch="select"name="customer">
21. <columnnamecolumnname="CUSTOMER_id"precision="18"scale="0"/>
22. </many-to-one>
23. <propertygeneratedpropertygenerated="never"lazy="false"name="orderNumber"type="java.lang.String">
24. <columnlengthcolumnlength="50"name="ORDER_NUMBER"/>