0

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=?

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

I would recommend you to use secondary tables instead like this:

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

    @Id
    @Column(name = "name")
    private String name;    
    
    @Column(table = "lastLogin", name = "date")
    private LocalDateTime date;
}

Also see https://www.baeldung.com/jpa-mapping-single-entity-to-multiple-tables for more details.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.