简体   繁体   中英

How to fix failed to lazily initialize a collection

When i try to get data from db about user, i get the following error:

Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed
    to lazily initialize a collection of role: com.hramyko.finalapp.entity.CommonUser.comments, could not initialize
    proxy - no Session

I know that happened bcs my session is closed, but i don't want to use eager fetch. What methods are there to solve my problem? I read the solution to my problem on stackoverflow, but it does not help me.

My CommonUser class:

package com.hramyko.finalapp.entity;

import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Entity
@Table(name = "common_users")
public class CommonUser extends User {

@OneToMany(mappedBy = "author")
private List<Comment> comments;

public CommonUser() {
}

public CommonUser(User user) {
    super(user.getEmail(), user.getPassword(), user.getFirstName(), user.getLastName(),
            user.getCreatedAt(), user.getRole(), user.getStatus());
    this.id = user.getId();
}

public CommonUser(String email, String password, String firstName,
              String lastName, Date createdAt, Role role, Status status, List<Comment> comments) {
    super(email, password, firstName, lastName, createdAt, role, status);
    this.comments = comments;
}

public List<Comment> getComments() {
    return comments;
}

public void setComments(List<Comment> comments) {
    this.comments = comments;
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    if (!super.equals(o)) return false;
    CommonUser that = (CommonUser) o;
    return Objects.equals(comments, that.comments);
}

@Override
public int hashCode() {
    return Objects.hash(super.hashCode(), comments);
}

@Override
public String toString() {
    return "CommonUser{" +
            "id=" + id +
            ", email='" + email + '\'' +
            ", firstName='" + firstName + '\'' +
            ", lastName='" + lastName + '\'' +
            ", comments=" + comments +
            ", createdAt=" + createdAt +
            ", role=" + role +
            '}';
}

}

Service:

@Transactional
@Override
public User currentUser() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String username;
    if (principal instanceof UserDetails) {
        username = ((UserDetails) principal).getUsername();
    } else {
        username = principal.toString();
    }
    return userRepository.findUserByEmail(username);
}

@Transactional
@Override
public User findUserByEmail(String email) {
    userValidator.validateEmail(email);
    return userRepository.findUserByEmail(email);
}

Controller:

@PreAuthorize("hasAnyAuthority('user.read', 'user.write', 'user.delete')")
@GetMapping("my_account")
public String show() {
    return userService.currentUser().toString();
}

It is because you are accessing comments in User 's toString() but the comments are not initialised yet and the transaction that load the user is already closed.

Typically two ways to solve it:

  1. Use fetch join to also fetch the comments when loading this user

  2. Increase the transaction boundary to cover the controller 's show() method such that when you access user.toString() in it, the transaction that load the user is still active and not closed yet:

@Transactional
public String show() {
    return userService.currentUser().toString();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM