Some explanations on lazy loading (one-to-one)

Some explanations on lazy loading

 

Generality

This page try to explain how lazy loading work in Hibernate.

 

one-to-one

 

How to do it

Use

<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

class A {
    private Set bees;
    public Set getBees() {
        return bees;
    }

    public void setBees(Set bees) {
        this.bees = bees;
    }

}

class B {
    // Not important really
}

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

class B {
    private C cee;

    public C getCee() {
        return cee;
    }

    public void setCee(C cee) {
        this.cee = cee;
    }
}

class C {
    // Not important really
}

 

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.

-- Tks to Dimas (stolen from the forum)

 

Workarounds