Hibernate <>的一对多和多对一操作真的很方便如果系统采用Hibernate作为持久层完全可以把对应的一对多和多对一逻辑关系放在Hibernate里面控制减少数据库的负担而且也更清晰
多对一和一对多概念
其实这个概念上来说很简单比如一个客户可以有多个订单多个订单属于同一个客户就是最基本的一对多和多对一数据库使用中感觉多对一和一对多算是比较常见的逻辑关系了
我曾经做过一些数据库比如某些政府部门的其表单很设计的很简单粗糙甚至连主键都没有完全靠在事务层补全这些关系其实通过Hibernate持久层来实现逻辑关系也是很不错的方法下面的例子就是数据库逻辑上基本没有定义主要放在持久层里面这个也主要是我对数据库操作属于半通水的原因
数据库层
这里面有两个表单一个CUSTOMER客户表单一个是ORDERS订单表单生成客户表单这个是在SQLServer里面做的其实其他都一样因为逻辑关系在Hibernate上面id是主键非空其他可以为空
CREATETABLE[dbo][CUSTOMER](
[id][numeric]()NOTNULL
[name][varchar]()NULL
[age][int]NULL
CONSTRAINT[PK_CUSTOMER]PRIMARYKEY)
订单表单
id为主键非空CUSTOMER_id是对应客户主键也非空这里不做外键设置
CREATETABLE[dbo][ORDERS](
[id][numeric]()NULLPRIMARYKEY
[CUSTOMER_id][numeric]()NOTNULL
[ORDER_NUMBER][varchar]()NULL
[PRICE][numeric]()NULL
)
Hibernate设定
HIbernate里面一对多的对象体现是客户有一个集合setset里面放着对应订单而多对一体现是订单里面有一个CUSTOMER对象表明该订单所属的客户其中CUSTOMER类为
publicclassCustomerimplementsjavaioSerializable{
privateLongid;
privateStringname;
privateIntegerage;
privateSetrderses=newHashSet();
}
后面的getXXX和setXXX方法就省去了同样订单类就是
publicclassOrdersimplementsjavaioSerializable{
privateLongid;
privateCustomercustomer;
privateStringorderNumber;
privateDoubleprice;
}
而对应hbm文档就是map文档如下
CUSTOMERhbmxml
<!DOCTYPEhibernatemappingPUBLIC//Hibernate/HibernateMappingDTD//EN
mappingdtd>
<!
MappingfileautogeneratedbyMyEclipsePersistenceTools
>
<hibernatemapping>
<classnameclassname=onetomanyCustomertable=CUSTOMERschema=dbocatalog=DBTEST>
<idnameidname=idtype=javalangLong>
<columnnamecolumnname=idprecision=scale=/>
<generatorclassgeneratorclass=increment/>
</id>
<propertynamepropertyname=nametype=javalangString>
<columnnamecolumnname=namelength=/>
</property>
<propertynamepropertyname=agetype=javalangInteger>
<columnnamecolumnname=age/>
</property>
<setnamesetname=ordersesinverse=truelazy=truecascade=all>
<key>
<columnnamecolumnname=CUSTOMER_idprecision=scale=notnull=true/>
</key>
<onetomanyclassonetomanyclass=onetomanyOrders/>
</set>
</class>
</hibernatemapping>
这个里面其他都很简答了其中<generatorclass=increment/>表示主键值自动增加这个主要针对字符串对应的主要体现多对以的是
<setnamesetname=ordersesinverse=truelazy=truecascade=all>
<key>
<columnnamecolumnname=CUSTOMER_idprecision=scale=notnull=true/>
</key>
<onetomanyclassonetomanyclass=onetomanyOrders/>
</set>
其中set表示对应集合fetch和lazy主要是用来级联查询的而cascade和inverse主要是用来级联插入和修改的这几个主要包括对集合的控制<onetomanyclass=onetomanyOrders/>表示对应类即set里面包含的类而key主要是用于确定set里面对应表单列
ORDERS的hbm
<?xmlversionxmlversion=encoding=utf?>
<!DOCTYPEhibernatemappingPUBLIC//Hibernate/HibernateMappingDTD//EN
mappingdtd>
<!
MappingfileautogeneratedbyMyEclipsePersistenceTools
>
<hibernatemapping>
<classcatalogclasscatalog=DBTESTname=onetomanyOrdersschema=dbotable=ORDERS>
<idnameidname=idtype=javalangLong>
<columnnamecolumnname=idprecision=scale=/>
<generatorclassgeneratorclass=increment/>
</id>
<manytooneclassmanytooneclass=onetomanyCustomerfetch=selectname=customer>
<columnnamecolumnname=CUSTOMER_idprecision=scale=/>
</manytoone>
<propertygeneratedpropertygenerated=neverlazy=falsename=orderNumbertype=javalangString>
<columnlengthcolumnlength=name=ORDER_NUMBER/>
</property>
<propertygeneratedpropertygenerated=neverlazy=falsename=pricetype=javalangDouble>
<columnnamecolumnname=PRICEprecision=scale=/>
</property>
</class>
</hibernatemapping>
<manytooneclassmanytooneclass=onetomanyCustomerfetch=selectname=customer>
<columnnamecolumnname=CUSTOMER_idprecision=scale=/>
</manytoone>
表示CUSTOMER熟悉对应的类和其作为key的列名上面这些都可以在MyEclipse里面自动生成另外注意的一点是在生成的DAO里面涉及表单操作的save()和delete()方法必须要事件提交数据库才有反映可以就该Hibernatexml或者用下面这样代码来实现
Sessionse=getSession();
Transactiontx=sebeginTransaction();
sedelete(persistentInstance);
//sesave(instance);
mit();
验证效果
新增用户
如果新增一个用户该用户里面包含有两个表单那么由于持久层已经实现了逻辑关系只要用户类里面的set包含了表单则表单可以自动增加实现代码
CustomerDAOcd=newCustomerDAO();
Customerxd=newCustomer(王小虎null);
Ordersord=newOrders();
ordsetCustomer(xd);
ordsetOrderNumber(王小虎的买单);
Ordersord=newOrders();
ordsetCustomer(xd);
ordsetOrderNumber(王小虎的买单);
Setrderses=newHashSet();
ordersesadd(ord);
ordersesadd(ord);
xdsetOrderses(orderses);
cdsave(xd);
代码里面加入一个王小虎用户两个订单通过setOrderses加入只使用cdsave这一个对持久层操作完成后查询
王小虎
=================================
王小虎的买单
王小虎的买单
显示CUSTOMER里面加入了王小虎ORDERS里面也加入他的订单
删除操作
List<Customer>csList=cdfindByProperty(name王小虎);
for(Customercs:csList){
cddelete(cs);
}
这个很简单了通过其中findByProperty(name王小虎);对应SQL为deletefromtableCUSTOMERwherename=王小虎;删除了王小虎而ORDERS里面王小虎对应的表单也同时被删除
小小总结
Hibernate的多对一和一对多处理还是挺方便的如果在减少数据库复杂度的原则来说把一些逻辑处理放在持久层是一个常见的方法