JPA LazyInitializationException jak zaradzić?

0

Hej. Mam relacje @OneToMany do @ManyToOne Post do postComments. W obydwu encjach fetch mam ustawiony na lazy. Mam metodę, która ma mi wyświetlić wszystkie komentarze z postu.

@Service
@RequiredArgsConstructor
public class PostService {

    private final PostRepository postRepository;

    @Transactional
    void printPostComments(Long postId) {
        postRepository.findById(postId).stream()
                .map(Post::getComments)
                .flatMap(Set::stream)
                .forEach(System.out::println);
    }
}

Nie rozumiem tylko czemu przy wywołaniu tej metody dostaje wyjątek LazyInitializationException. Jeśli dobrze rozumiem @Transactional otwiera mi transakcje podczas wywołania metody i zamyka ją po jej zakończeniu. Więc gdy chce pobrać komentarze hibernate powinien mieć jeszcze możliwość odpytania o komentarze?

Załączam jeszcze encje:

public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @Builder.Default
    @OneToMany(
            mappedBy = "post",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private Set<PostComment> comments = new HashSet<>();

    public void addComment(PostComment newComment) {
        comments.add(newComment);
        newComment.setPost(this);
    }

    public void removeComment(PostComment newComment) {
        comments.remove(newComment);
        newComment.setPost(null);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Post post = (Post) o;
        return Objects.equals(id, post.id);
    }

    @Override
    public int hashCode() {
        return 0;
    }
}

public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

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

    @Override
    public int hashCode() {
        return 0;
    }

    @Override
    public String toString() {
        return "PostComment{" +
                "review='" + review + '\'' +
                '}';
    }
}
1
  1. Dlaczego ta metoda jest transactional?
  2. Dlaczego pojedynczy element typu Optional zamieniasz na stream?
1

Na marginesie wątku, zerowy hashCode to kopnie w ...ę wcześniej czy później (dziwne, bo przyłożyłeś się do equalsa). Jak się nie ma ochoty skończyć tej pary poprawnie, to sie nie realizuje wcale.

A o @Transactional można pisać sensacyjne powieści. Ze złym zakończeniem.

0

@AnyKtokolwiek: odnośnie equals I hashcode sugerowałem się tym postem https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
Wydaje mi się że podejście jest poprawne.

@Korges
Ad. 1 żeby pobrać komentarze
Ad. 2 żeby mieć stream komentarzy aby je wyświetlić.

Ogólnie to utworzyłem ten przykład tylko w celu żeby zademonstrować mój problem.

0
barslo napisał(a):

@AnyKtokolwiek: odnośnie equals I hashcode sugerowałem się tym postem https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
Wydaje mi się że podejście jest poprawne.

Ta para metod w JPA to szerokie zagadnienie, największym problemem jest tożsamość obiektu przez zapisem, gdy nie ma ostatecznego ID.
Wiem, ze są różne propozycje rozwiązania - własnego zdania nie mam

2

@Transactional zapewne tu nie działa.

I nawet wiem czemu, ale widzę, że w komentarzu do postu oryginalnego, już ktoś zauważył dlaczego.
Uzupełnie swoją listę o przypadek package access - trudniej dostrzec niż private.

1 użytkowników online, w tym zalogowanych: 0, gości: 1