|
outer-join属性在hibernate表示迫切左外连接检索。
在xdoclet生成hibernate的hbm文件的时候,对持久化对象的关联对象(包括one-to-one,one-to-many,many-
to-one,many-to-many等等),如果不指定outer-join的值的话,默认值为outer-join=auto。
然而,在使用过程中,我发现,对于outer-join=auto的情况,经常会发生错误。比如说many-to-one、one-to-many的关联
对象无法加载(对于集合已设定lazy=false,采用立即检索,理论上说与outer-join=auto联合应该能立即加载关联对象),当时没做总
结,具体在什么条件下产生问题我已经忘了,不过根源可能跟我下面想要说的问题的根源一致。
在这里主要想说得是针对many-to-many中outer-join取值不同所导致的一些问题,发在这里,权作备忘。系统使用的hibernate版本是3.0.3
先看看下面一个有意思的例子(从hbm文件可以看出模型结构,我就不贴了,dao,manager之类的也不贴了,这些都不是主要问题,数据库事务是在manager类中实现的)
TestRange.hbm.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-cascade="none" auto-import="true">
<class node="testRange" name="application.model.TestRange" table="t_testrange" dynamic-update="false" dynamic-insert="false" select-before-update="false" optimistic-lock="version" mutable="true" polymorphism="implicit" batch-size="1">
<id node="id" name="id" type="java.lang.Long" unsaved-value="null">
<column name="testrange_id"/>
<generator class="native">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-TestRange.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>
<property node="name" name="name" type="string" update="true" insert="true" access="property" not-null="false" unique="false">
<column name="name" length="50"/>
</property>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-TestRange.xml
containing the additional properties and place it in your merge dir.
-->
<joined-subclass name="application.model.TestGroup" table="t_testgroup" dynamic-update="false" dynamic-insert="false">
<key column="testrange_id"/>
<set node="." lazy="false" name="testSet" table="t_tgroup_trange" inverse="false" cascade="save-update" sort="unsorted" batch-size="1" outer-join="auto">
<key column="testgroup_id">
</key>
<many-to-many node="testRange" embed-xml="true" class="application.model.TestRange" column="testrange_id" outer-join="auto"/>
</set>
</joined-subclass>
<joined-subclass name="application.model.Test" table="t_test" dynamic-update="false" dynamic-insert="false">
<key column="testrange_id"/>
<property node="num" name="num" type="int" update="true" insert="true" access="property" not-null="false" unique="false">
<column name="num"/>
</property>
<property node="val" name="val" type="string" update="true" insert="true" access="property" not-null="false" unique="false">
<column name="val"/>
</property>
</joined-subclass>
</class>
</hibernate-mapping>
一共3个持久化对象模型,TestRange是父类,包含id和name属性,Test和TestGroup是子类,TestGroup中有一个关系为many-to-many的Set,元素为TestRange。
目前set的outer-join=auto,many-to-many的outer-join=auto
看下面测试用例:
public class TestManagerTester extends TestCase {
private TestManager _mgr;
protected void setUp() throws Exception {
super.setUp();
_mgr=(TestManager)BeanFactoryWrapper.getBean(TestManager.class.getName());
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testManager() {
assertNotNull(_mgr);
List list=_mgr.getTestRanges();
if(list.isEmpty()){
Test test=new Test();
test.setName("abc");
test.setNum(5);
Test test2=new Test();
test2.setNum(6);
TestGroup group=new TestGroup();
group.setName("name");
group.getTestSet().add(test);
group.getTestSet().add(test2);
_mgr.saveTestRange(group);
list=_mgr.getTestRanges();
}
assertNotNull(list);
assertTrue(list.size()>=1);
Iterator iter=list.iterator();
while (iter.hasNext()){
Object obj=iter.next();
// assertTrue(obj instanceof TestGroup);
if(obj instanceof TestGroup){
Set set=((TestGroup) obj).getTestSet();
if(!set.isEmpty()){
Iterator iter2=set.iterator();
while(iter2.hasNext()){
Object obj2=iter2.next();
System.out.println("element value is "+obj2);
System.out.println("in set element class is "+obj2.getClass());
//assertTrue(obj2 instanceof Test);
}
}
}
}
}
}
group的testSet中有2个元素test和test2,test2.name=null,test.name="abc",测试用例运行结果是:
element value is application.model.Test@106df95[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.TestRange$$EnhancerByCGLIB$$3119c08f
element value is application.model.Test@176086d[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.Test
也就是说,对于name为空的集合元素的class有问题,不是正常的Test类,而是CGLIB生成的一个什么类(toString显示的却是正常
的),通过其他测试用例发现,对于set和many-to-many的outer-join均为auto的时候,many-to-many的class为
父类,只要在集合元素中有一个(或以上) 的父类属性值为空,而实际类型为子类的时候,得到的元素的class都有问题。
对hbm文件进行修改,方法如下:
1 把many-to-many的outer-join改为false,结果同上
2 把many-to-many的outer-join改为true,其余不变,测试用例运行结果是:
element value is application.model.Test@16f5261[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.Test
element value is application.model.Test@176086d[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.Test
也就是说结果符合我们的实际需要。
3 many-to-many的outer-join=auto, set的outer-join=true,结果
element value is application.model.Test@1e1ec86[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.TestRange$$EnhancerByCGLIB$$b004439a
element value is application.model.Test@15a94f[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.TestRange$$EnhancerByCGLIB$$b004439a
嘿嘿都错了。
4 many-to-many的outer-join=true, set的outer-join=true 结果
element value is application.model.Test@1304043[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.Test
element value is application.model.Test@15a94f[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.Test
都对的
5 many-to-many的outer-join=true, set的outer-join=false 结果
element value is application.model.Test@16f5261[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.Test
element value is application.model.Test@176086d[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.Test
6 many-to-many的outer-join=auto, set的outer-join=false 结果
element value is application.model.Test@106df95[id=6,name=<null>,num=6,val=<null>]
in set element class is class application.model.TestRange$$EnhancerByCGLIB$$13cc6038
element value is application.model.Test@176086d[id=5,name=abc,num=5,val=<null>]
in set element class is class application.model.Test
test.name=null时出错。
列了这么多现象,等有空时再看源码找问题的根源。
目前我避免问题采取的策略就是尽量不用outer-join=auto选项。 |