Hibernate <http://developer.51cto.com/art/200611/34245.htm>的一對多和多對一操作真的很方便,如果系統採用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"/>
25.</property>
26.<propertygeneratedpropertygenerated="never"lazy="false"name="price"type="java.lang.Double">
27.<columnnamecolumnname="PRICE"precision="18"scale="3"/>
28.</property>
29.</class>
30.</hibernate-mapping>
31.<many-to-oneclassmany-to-oneclass="onetomany.Customer"fetch="select"name="customer">
32.<columnnamecolumnname="CUSTOMER_id"precision="18"scale="0"/>
33.</many-to-one>
表示CUSTOMER熟悉對應的類,和其作為key的列名,上面這些都可以在MyEclipse裡面自動生成.另外注意的一點是,在生成的DAO裡面,涉及表單操作的save()和delete()方法,必須要事件提交,資料庫才有反映.可以就該Hibernate.xml,或者用下面這樣代碼來實現:
34.Sessionse=getSession();
35.Transactiontx=se.beginTransaction();
36.se.delete(persistentInstance);
37.//se.save(instance);
38.tx.commit();
4、驗證效果
1、新增用戶
如果新增一個用戶,該用戶裡面包含有兩個表單,那麼,由於持久層已經實現了邏輯關係,只要用戶類裡面的set包含了表單,則表單可以自動增加.實現代碼:
39.CustomerDAOcd=newCustomerDAO();
40.Customerxd=newCustomer("王小虎",20,null);
41.Ordersord1=newOrders();
42.ord1.setCustomer(xd);
43.ord1.setOrderNumber("王小虎的買單1");
44.Ordersord2=newOrders();
45.ord2.setCustomer(xd);
46.ord2.setOrderNumber("王小虎的買單2");
47.Setrderses=newHashSet();
48.orderses.add(ord1);
49.orderses.add(ord2);
50.xd.setOrderses(orderses);
51.cd.save(xd);
代碼裡面,加入一個王小虎用戶.兩個訂單,通過setOrderses加入,只使用cd.save這一個對持久層操作.完成後查詢:
52.王小虎
53.=================================
54.王小虎的買單1
55.王小虎的買單2
顯示,CUSTOMER裡面加入了王小虎,ORDERS裡面也加入他的訂單.
2、刪除操作
56.List<Customer>csList=cd.findByProperty("name","王小虎");
57.for(Customercs:csList){
58.cd.delete(cs);
59.}
這個很簡單了,通過其中findByProperty("name","王小虎");對應SQL為deletefromtableCUSTOMERwherename=''王小虎';刪除了王小虎,而ORDERS裡面,王小虎對應的表單也同時被刪除.
5、小小總結
Hibernate的多對一和一對多處理,還是挺方便的,如果在減少資料庫複雜度的原則來說,把一些邏輯處理放在持久層是一個常見的方法.
[火星人 ] Hibernate的多對一和一對多操作實例已經有985次圍觀