Использование FetchType и JOIN FETCH при аннотировании моделей и написании JPQL-запросов

Рейтинг: 0Ответов: 0Опубликовано: 10.08.2025

Всем доброго времени суток.

Контекст: Изучаю Java, имея какой-то опыт в работе с СУБД. В изучаемом примере есть следующие классы:

Comment.java:

@Entity
@Table(name="comments")
@Getter
@Setter
public class Comment {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false, updatable = false)
  private Long id;
  
  @ManyToOne
  @JoinColumn(name = "post_id", referencedColumnName = "id")
  private Post post;
}

Post.java:

@Entity
@Table(name = "posts")
@Getter
@Setter
public class Post {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false, updatable = false)
  private id;
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
  private List<Comment> comments;
}

CommentRepository.java:

public interface CommentRepository extends JpaRepository<Comment, Long> {

  Collection<Comment> findAllByPostId(Long postId);
  
  @Query("SELECT c "
         + "FROM Comment AS c "
         + "JOIN c.post AS p "
         + "WHERE p.id IN :id_list")
  Collection<Comment> findAllByPostIdIn(@Param("id_list") Itterable<Long< postIds);
}

PostRepository.java:

public interface PostRepository extends JpaRepository<Post, Long> {
}

Задача #1: "Вернуть все комментарии по идентификатору поста" решается легко:

@RequiredArgsConstructor
@Service
public class CommentService {
  
  private final CommentRepository commentRepository;
  
  public Collection<Comment> getAllByPost(Post post) {
    return commentRepository.findAllByPostId(postId.getId());
  }
}

Задача #2: "Вернуть все комментарии по коллекции идентификаторов постов" так же решается легко:

@RequiredArgsConstructor
@Service
public class CommentService {
  
  private final CommentRepository commentRepository;
  
  public Collection<Comment> getAllByPosts(List<Long> postIds) {
    return commentRepository.findAllByPostIdIn(postIds);
  }
}

Здесь всё понятно - задачи тривиальные и решаются легко. Они будут тянуть за собой поля таблицы posts, т.к. по полю из этой таблицы осуществляется поиск.

Но это будет повторяться при всех запросах к Comment, даже когда нет необходимости получать значения полей из таблицы posts. К примеру, в методе CommentRepository.findAll(), который используется для вывода всех комментариев из БД без указания на родительский Post (ну просто виртуальная задача в вакууме). В выборку так же попадут поля из таблицы posts, хотя в условиях запроса или обработке на стороне сервиса они участвовать не будут. Это решается с помощью указания FetchType.LAZY в соответствующих свойствах и использовании JOIN FETCH при написании JPQL-запросов:

Comment.java (после изменений):

@Entity
@Table(name="comments")
@Getter
@Setter
public class Comment {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false, updatable = false)
  private Long id;
  
  @ManyToOne
  @JoinColumn(name = "post_id", referencedColumnName = "id", fetch=FetchType.LAZY)
  private Post post;
}

Post.java (после изменений):

@Entity
@Table(name = "posts")
@Getter
@Setter
public class Post {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false, updatable = false)
  private id;
  
  @OneToMany(fetch = FetchType.LAZY, mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
  private List<Comment> comments;
}

CommentRepository.java (после изменений):

public interface CommentRepository extends JpaRepository<Comment, Long> {

  @Query("SELECT c "
         + "FROM Comment AS c "
         + "JOIN FETCH c.post AS p "
         + "WHERE p.id = :post_id")
  Collection<Comment> findAllByPostId(@Param("post_id") Long postId);
  
  @Query("SELECT c "
         + "FROM Comment AS c "
         + "JOIN FETCH c.post AS p "
         + "WHERE p.id IN :id_list")
  Collection<Comment> findAllByPostIdIn(@Param("id_list") Itterable<Long< postIds);
}

Но как быть, если мне надо получить коллекцию из таблицы posts, где к каждому экземпляру Post должна быть прикреплена коллекция Comment, с учётом, что у меня теперь используется FetchType.LaZY?

PostService.java:

@RequiredArgsConstructor
@Service
public class PostService {
  
  private final PostRepository postRepository;
  
  public Collection<Post> getAll(List<Long> postIds) {
    return commentRepository.findAllWithItemsByPostIdIn(postIds);
  }
}

Правильно ли будет использовать JOIN FETCH в этом JPQL-запросе?

PostRepository.java:

public interface PostRepository extends JpaRepository<Post, Long> {
  
  @Query("SELECT p "
         + "FROM Post AS p "
         + "JOIN FETCH p.comments AS c "
         + "WHERE p.id IN :id_list")
  Collection<Post> findAllWithItemsByPostIdIn(@Param("id_list") Itterable<Long> postIds);
}

Или есть какое-то более корректное решение?

Ответы

Ответов пока нет.