Use
1.
<one-to-one constrained="true" outer-join="false" class="Foo"/>
with a proxied class, Foo. This
is ONLY conceptually possible for a mandatory association since we have to hit
the other table to determine whether the association is null or not!
Why
having this limitation ?
Think about how lazy
one-to-many is implemented. Suppose you have
1.
class A {
2.
private Set bees;
3.
public Set getBees() {
4.
return bees;
5.
}
6.
7.
public void setBees(Set bees) {
8.
this.bees = bees;
9.
}
10.
11. }
12.
13. class B {
14. // Not important really
15. }
What
happens when Hibernate loads object of class A? It creates special Set wrapper
which is not initialized yet. Then it sets this wrapper to "bees" (a.setBees(wrapper)).
Right
after loading A you may call getBees() and get
this set. This Set object is NEVER null. But it is not loaded from the database yet. When you perform
first meaningful action on this set (size(), iterate(), etc)
Hibernate loads corresponding objects from the database and initializes set.
This is possible because Hibernate subclasses HashSet or
something like that and override all meaningful operations to know someone
needs the real data.
Now consider our class B
has one-to-one association to C
1.
class B {
2.
private C cee;
3.
4.
public C getCee() {
5.
return cee;
6.
}
7.
8.
public void setCee(C cee) {
9.
this.cee = cee;
10. }
11. }
12.
13. class C {
14. // Not important really
15. }
Right
after loading B, you may call getCee() to
obtain C. But look, getCee() is a
method of YOUR class and Hibernate has no control over it. Hibernate does not
know when someone is going to call getCee(). That means Hibernate must put an appropriate value into
"cee" property at the moment it loads B from database.
If
proxy is enabled for C, Hibernate can put a C-proxy object which is not loaded
yet, but will be loaded when someone uses it. This gives lazy loading for one-to-one.
But now
imagine your B object may or may not have associated C (constrained="false"). What should getCee() return when specific B does not have C? Null. But remember,
Hibernate must set correct value of "cee" at the moment it set B
(because it does no know when someone will call getCee()). Proxy does not help here because proxy itself in already
non-null object.
So the
resume: if your B->C mapping is mandatory (constrained=true),
Hibernate will use proxy for C resulting in lazy initialization. But if you
allow B without C, Hibernate just HAS TO check presence of C at the moment it
loads B. But a SELECT to check presence is just inefficient because the same
SELECT may not just check presence, but load entire object. So lazy loading
goes away.
Workaround1 : - Just add annotation or entry in hdm file
for
@JoinColumn for reference
private Address address;
.
Workaround2 :- add optional=false in
OneToOne
relationship
If the
association is optional, Hibernate has no way to know if an address exists for
a given person without issuing a query. So it can't populate the address field
with a proxy, because there could be no addres referencing the person, and it
can't populate it with null, because there might be an address referencing the
person.
When you make the associatio mandatory (i.e.
optional=false
), it
trusts you and assumes that an address exists, since the association is
mandatory. So it directly populates the address field with a proxy, knowing
that there is an address referencing the person.
Other solutions for this problem:
The simplest one is to fake
one-to-many relationship. This will work because lazy
loading of collection is much easier then lazy loading of single nullable
property but generally this solution is very inconvenient if you use complex
JPQL/HQL queries.
The other
one is to use build time bytecode instrumentation. For more
details please read Hibernate documentation: 19.1.7. Using lazy property
fetching. Remember that in this case you have to add
@LazyToOne(LazyToOneOption.NO_PROXY)
annotation to one-to-one relationship to make
it lazy. Setting fetch to LAZY is not enough.
The last
solution is to use runtime bytecode instrumentation but it
will work only for those who use Hibernate as JPA provider in full-blown JEE
environment (in such case setting "
hibernate.ejb.use_class_enhancer
" to
true should do the trick: Entity Manager Configuration) or use Hibernate with
Spring configured to do runtime weaving (this might be hard to achieve on some
older application servers). In this case @LazyToOne(LazyToOneOption.NO_PROXY)
annotation is also required.
This will
work for you.
Honestly speaking this blog is absolutely amazing in learning the subject that is building up the knowledge of every individual and enlarging to develop the skills which can be applied in to practical one. Finally, thanking the blogger to launch more further too.
ReplyDeleteJava Training in Chennai
Java Course in Chennai