There are different ways for lazy initialisation in Hibernate. One of the common practices is:
public class Student { @OneToMany(fetch = FetchType.LAZY) private List<Book> books; @OneToOne(fetch = FetchType.LAZY) private Address address; } public class Book { @ManyToOne(fetch = FetchType.LAZY) private Student student; }
So, what happens with this lazy initialisation? Lets look in deep one by one.
@OneToMany
Considering the above example when Student is loaded from DB a proxy of empty Book list is returned instead of book list. It is only loaded when the Book list is accessed.
@ManyToOne
In case of ManyToOne, when Book is loaded from DB, hibernate checks the foreign key. If the foreign key is not null a proxy is injected instead of Student from DB.
@OneToOne
The lazy initialisation doesn’t work with above OneToOne mapping example. The reason is when hibernate loads Student it doesn’t know whether Address should be injected by proxy or keep it null.
The bytecode instrumentation (compile time instrumentation) is the solution for this.
Another solution is to make it required as:
@OneToOne(fetch = FetchType.LAZY, optional = false)
When it constrained, the hibernate can easily inject a proxy. So, lazy initialisation works fine. But the issue arise when it doesn’t fit with business requirement. Therefore we must find another way to keep it lazy.
Another hackish way is making it a @OneToMany relationship and then hibernate can inject a proxy of empty list.
Or you can keep foreign key in both side of the one-to-one relation.
Be lazy, be happy… 🙂