Home > other >  Hibernate bidirectional @OneToOne always EAGER on child side
Hibernate bidirectional @OneToOne always EAGER on child side

Time:11-06

I have two entities: Person and Passport. I map it as bidirectional.

Passport (parent):

@Entity
@Table(name = "passports")
public class Passport {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private Integer serial;
    private Integer number;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_id", referencedColumnName = "id")
    private Person person;

Person (child):

@Entity
@Table(name = "people")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;

    @OneToOne(mappedBy = "person", fetch = FetchType.LAZY)
    private Passport passport;

Both relations fetch types are LAZY.

Now I'm trying to find only child:

Person p = entityManager.find(Person.class, 1);
System.out.println(p.getName());

Hibernate generates two SELECT statements instead of one (must select only person).

Hibernate: select p1_0.id,p1_0.name from people p1_0 where p1_0.id=?
Hibernate: select p1_0.id,p1_0.number,p1_0.person_id,p1_0.serial from passports p1_0 where p1_0.person_id=?

I expect only one select, but get two.

Why doesnt LAZY work? What am I doing wrong?

CodePudding user response:

For all other relation types, FetchType.LAZY will work as expected, but for @OneToOne it is different.

It would work if you change your Person entity such that you don't have relation to Passport, and in Passport have:

@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Person person;

Then if you are using Spring JPA and you want to find a Passport for a Person, you can do passportRepository.findByPerson(person).

Or if you are using entityManager, you can find it as:

entityManager.find(Passport.class, person.getId());

For more explanation, please read https://thorben-janssen.com/hibernate-tip-lazy-loading-one-to-one/.

  • Related