Search code examples
spring-boothibernatespring-data-jpaspring-dataone-to-one

LazyInitializationException when get EAGER fetch object OneToOne


I have two entity

@Entity
@Table(name = "user")
@Data
@Builder
@EqualsAndHashCode(callSuper=false)
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "name")
    private String name;    
    
    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @PrimaryKeyJoinColumn
    private UserLastLogin userLastLogin;
}


@Entity
@Table(name = "lastLogin")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserLastLogin implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "name")
    private String userName;

    @Column(name = "date")
    private LocalDateTime date;

    @OneToOne
    @MapsId
    @JoinColumn(name = "name")
    private User user;

}

I use spring boot with spring data and jpa, hibernate in latest version. In documentation is that @OneToOne is default EAGER, but when i get eager fetch object, i get lazyInitializationException when i not use @Transactional in get method. I don't understant why...

    public UserDto getUser(String userName) {
        var user= userRepository.getById(userName);     
        d.getSystemUserLastLogin(); // this throw lazy initialization exception
        return mapper.entityToDto(d);
    }

When i'will mark this method @Transactioal, this work. But, not recommendend used transactions in get method. I need use EAGER fetch in this relationship.

When i view query hibernate, i have one select, but children object is not available.

Hibernate: 
    select
        user0_.name as nazwa1_4_0_,        
        user2_.name as name1_23_2_,        
        user2_.data as data3_23_2_ 
    from
        user0_     
    left outer join
       last_login user2_ 
            on user0_.name=user2_.name 
    where
        user0_.name=?

Solution

  • The problem was that despite the fetch eager, lazy was used. This was due to the use of the getById method from the repository, which retrieves only the object's references and snaps all the fields when lazy is retrieved. Changing to findById solves the problem as findById takes an object, not a reference.