Использование FetchType и JOIN FETCH при аннотировании моделей и написании JPQL-запросов
Всем доброго времени суток.
Контекст: Изучаю 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);
}
Или есть какое-то более корректное решение?