Jan 18 2008

hibernate 的 one to zero or one

Category: 技术ssmax @ 18:44:35

hibernate能支持这种方式,一对零或一,但是不能做到lazy,今天搞cdr搞了一天,锁死在这个问题上面了,暂时无解

 cdr的表已经400多w数据了,而且字段有nn个,这次新加的属性也不是每条都用到,所以是一个one to zero or one的关系,但是hibernate怎么搞都不能做到lazy,这样如果搜索很多cdr的时候就造成join表或者select过多。。。很郁闷。到官方论坛找了一下,貌似这个问题暂时无解。。。摘录一点评论:

from http://forum.hibernate.org/viewtopic.php?t=949458

1、

The problem is that sometimes we really need a lazy “one-to-zero-or-one” relationship. If we would change to a lazy one-to-one we would have to use the constrained attribute in ‘one-to-one’ element which forces a not null attribute. But sometimes a person doesn’t have a note.The use of “many-to-one” mapping that we did fits perfectly to our needs. It gets a proxy when we don’t use eager fetching. It gets the right note when we use eager fetching, but it gets a proxy when there is no note associated to the person. So it works almost perfectly, except that when we force eager fetching in null notes, Hibernate hydrates person objects with a proxy and not with a null reference.I know that I could add a FK in note table and solve my problem, but why should I do that if I can use the same person PK? If Hibernate would return null when there is no note it would be just right. I just would like that the following mapping should work as stated above. I think that when we get a proxy when an eager fetching is used is an inconsistent result. In our case, we are using a workaround to detect and fix this situation, but we wanted to report it as a way to help other people who may face the same problem and maybe to help Hibernate become even better.Many-to-one mapping:

<many-to-one name=”note” class=”Note” column=”id”
                   unique=”true” insert=”false” update=”false”
                   cascade=”all”/>

Our problem is not so rare. We found other people in this forum facing the same lazy “one-to-zero-or-one” problem, but the solutions were “non-lazy one-to-one mapping”, “lazy not-null one-to-one mapping using constrained=”true”” or “many-to-one mapping using a foreign key (FK)”. We are suggesting one more solution to the problem: “many-to-one mapping using the same primary key (PK)”. I hope that can help someone else.
 

2、

Hibernate cannot replace a proxy with a null, this is not possible in Java wo bytecode enhancement.
So wo does hibernate know whether it needs to create a proxy or set null? The only solution is to load the second row. Check the wiki comunity area, there is a page dedicated to the non one-to-one lazyness

3、 The use of not-found=”ignore” results in a non-lazy property. So lazy “one-to-zero-or-one” in Hibernate is not possible yet. We can use non-lazy “one-to-zero-or-one” or a lazy one-to-one association. 4、hibernate teamHi guys,Just a small comment – there is *no* problem in using polymorpishm with respect to associations in hibernate. The issue you have is about representing NULL, something that is more related to the kind of datamodelling people tend to do and not OO. The users I see having problem with polymorphic associations are mostly those who want to downcast their objects which again is something that is arguable OO.And note, that just because there *can* be a association defined between two objects, doesnt mean it *has* to be physically represented in your object model.In any case, all is possible now with H3.1, so go buy your bigger machines 😉

补充:

下班前终于想到一个临时方法搞定。。。贴到hibernate。。。用one to many 来实现,会好看一点,呵呵

i think i have this problem today , i don’t know whether hibernate team has resolved this problem or not after two years…(the last post is 2005…)and i think a temp solution:
use one-to-many instead , i think one to many includes one to zero or one or many….
and for one to zero or one , wirte a bean method to handle the Set/List and get the real one value….
<set name=”notes” table=”Note” inverse=”true” lazy=”true”>
<key column=”owner”></key>
<one-to-many class=”Note”/>
</set>

and you have a
Set getNotes() in the module

add a method:

Note getNote() {
if(notes == null) return null;
else if(notes.size()>0)return notes.iterator().next();
else return null;
}