9

I have an Employee and Address with one-to-one bi-directional mapping:

@Entity
public class Employee {
    @Id
    @Column(name = "EMP_ID")
    private long id;

    private String firstName;
    private String lastName;
    private double salary;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ADDRESS_ID")
    private Address address;
}

Below is my address entity:

@Entity
public class Address {
    @Id
    @Column(name = "ADDRESS_ID")
    private long id;

    private String street;
    private String city;
    private String province;
    private String country;
    private String pinCode;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "address")
    private Employee owner;
}

In Address I have set Fetch type as Lazy. So if I get an address then I am expecting hibernate to run select query on address only, but I see in logs that it is trying to get Employee also.

Below is my HQL query:

List<Address> emps = session.createQuery("from Address where id=20").list();

These are the queries run by Hibernate:

Hibernate: 
    /* 
from
    Address 
where
    id=20 */ select
        address0_.ADDRESS_ID as ADDRESS_1_0_,
        address0_.city as city2_0_,
        address0_.country as country3_0_
    from
        Address address0_ 
    where
        address0_.ADDRESS_ID=20
Hibernate: 
    /* load Employee */ select
        employee0_.EMP_ID as EMP_ID1_1_0_,
        employee0_.ADDRESS_ID as ADDRESS_5_1_0_,
        employee0_.firstName as firstNam2_1_0_,
        employee0_.lastName as lastName3_1_0_
    from
        Employee employee0_ 
    where
        employee0_.ADDRESS_ID=?

Why hibernate loads Employee eagerly even when I set its fetching strategy as LAZY.

learner
  • 4,858
  • 9
  • 47
  • 92
  • you can refer the answer at http://stackoverflow.com/questions/1444227/making-a-onetoone-relation-lazy]. I think this post can help you. – tam nguyen Dec 27 '16 at 17:45

3 Answers3

5

This great article describes the problem and a possible solution:

https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

Possible solution: It must be a one-directional relationship from child to parent. The parent cannot have a @OneToOne field to access the child because:

"For every managed entity, the Persistence Context requires both the entity type and the identifier, so the child identifier must be known when loading the parent entity, and the only way to find the associated {child} primary key is to execute a secondary query."

Second solution: Use @OneToMany instead. Don't use @OneToOne because it has this complicated, subtle, quirky problem. You can alter the code to only allow one-to-one access and optionally add a unique key to enforce 1-1.

Curtis Yallop
  • 5,490
  • 3
  • 37
  • 27
1

Lazy loading on one-to-one mapping is possible either by

  1. Setting optional=false (If its not nullable) or
  2. JoinColumn (not on PK and might require schema change)

You can refer to this link for moreinfo.

Explanation : You can refer to explanation link for detailed explanation about this.

Kishore Bandi
  • 4,933
  • 1
  • 25
  • 41
-1

Newer version of hibernate can't use trick such as optional=false.

Checkout the updated solution best way to map a onetoone relationship

Neo Pham
  • 183
  • 2
  • 9
  • 1
    tried the suggestion with MapsId but the issue persists : the @OneToOne parameter is being eagerly loaded when I call a Spring repository. Sounds like a Hibernate bug – epol Aug 20 '19 at 19:30
  • "Newer version of hibernate can't use trick" do you have a reference for this? – Dirk Nov 12 '19 at 15:35