Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 845
VB_ Avatar asked Aug 01 '13 07:08

VB_


People also ask

What is optional false in Hibernate?

1. optional=false is not working if you try to save the Personne without Adresse : "org.hibernate.PropertyValueException: not-null property references a null or transient value: " – Grégory. Nov 28, 2013 at 18:30. optional = false means that... the address is not optional.

What is optional false?

optional=false is a runtime instruction. The primary functional thing it does is related to Lazy Loading.

Is lazy loading default in Hibernate?

1. Working with lazy associations. By default, Hibernate uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.

How do you make a OneToOne lazy?

You just have to set the fetch attribute of the @OneToOne association to FetchType. LAZY. But if you model this as a bidirectional association, you will quickly recognize that Hibernate always fetches the other end of the association eagerly.


2 Answers

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.

like image 84
JB Nizet Avatar answered Sep 30 '22 00:09

JB Nizet


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.

like image 23
sendon1982 Avatar answered Sep 29 '22 23:09

sendon1982