Hibernate: one-to-one lazy loading, optional = false

HibernateJpaLazy LoadingOne to-One

Hibernate Problem Overview


I faced the problem that one-to-one lazy loading doesn't work in hibernate. I've already solved it, but still don't properly understand what happens.

My code (lazy loading doesn't work here, when I pull Person - Address is also fetched):

@Entity
public class Person{

  @Id
  @SequenceGenerator(name = "person_sequence", sequenceName = "sq_person")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence")
  @Column(name = "id")
  private long personID;

  @OneToOne(mappedBy="person", cascade=CascadeType.ALL, fetch = FetchType.LAZY)
  private Adress address;
  //.. getters, setters
}

@Entity
public class Address {
  
  @Id
  @Column(name="id", unique=true, nullable=false)
  @GeneratedValue(generator="gen")
  @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
  private long personID;

  @PrimaryKeyJoinColumn
  @OneToOne
  private FileInfo person;
}

But: if I add optional=false in OneToOne relationship, lazy loading works fine!

@OneToOne(mappedBy="person", cascade=CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private Adress address;

Question/Entreaty: please, explain to me how optional=false annotation helps to achieve lazy loading.

P.S. I've read posts post1 and post2, and understand why simple OneToOne can't be lazy, but I still can't grasp optional=false magic.

Hibernate Solutions


Solution 1 - Hibernate

If the association is optional, Hibernate has no way of knowing 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 address referencing the person, and it can't populate it with null, because there might be an address referencing the person.

When you make the association 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.

Solution 2 - Hibernate

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVB_View Question on Stackoverflow
Solution 1 - HibernateJB NizetView Answer on Stackoverflow
Solution 2 - Hibernatesendon1982View Answer on Stackoverflow