I have the following entities.
Entity Models:
@Entity
@Getter
@Setter
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String categoryId;
@BatchSize(size = 20)
@ManyToMany
private List<Tag> tags = new ArrayList<>();
}
@Entity
@Getter
@NoArgsConstructor
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String name;
public Tag (String name) {
this.name = name;
}
}
And DTO:
@Getter
public class ArticleResponseDto {
private final int id;
private final List<TagDto> tags;
public ArticleResponseDto(Article article) {
this.id = article.getId();
this.tags = article.getTags().stream()
.map(TagDto::new)
.toList();
}
}
@Getter
class TagDto {
private final String name;
public TagDto(Tag tag) {
this.name = tag.getName();
}
}
In Hibernate 5.6.14, when querying articles, it generated queries :
Hibernate: select article0_.id as id1_0_, article0_.category_id as category2_0_ from article article0_ order by article0_.id DESC limit ?
Hibernate: select tags0_.article_id as article_1_1_1_, tags0_.tags_id as tags_id2_1_1_, tag1_.id as id1_2_0_, tag1_.name as name2_2_0_ from article_tags tags0_ inner join tag tag1_ on tags0_.tags_id=tag1_.id where tags0_.article_id in (?, ?, ?, ?, ?)
However In Hibernate 6.1.6:
Hibernate: select t1_0.article_id,t1_1.id,t1_1.name from article_tags t1_0 join tag t1_1 on t1_1.id=t1_0.tags_id where t1_0.article_id in(?,?,?,?,?)
Hibernate: select t1_0.article_id,t1_1.id,t1_1.name from article_tags t1_0 join tag t1_1 on t1_1.id=t1_0.tags_id where t1_0.article_id in(?,?)
Hibernate: select t1_0.article_id,t1_1.id,t1_1.name from article_tags t1_0 join tag t1_1 on t1_1.id=t1_0.tags_id where t1_0.article_id in(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
Hibernate 6.1.6 generated queries 2 more and binded data in each query were article-id that had empty tag list. And the values in IN clause at the last query was always generated as much as the size of @BatchSize
.
Test Code:
@SpringBootTest
@Transactional
class TestServiceTest {
@Autowired
private EntityManager entityManager;
@BeforeEach
void fixture() {
List<Tag> tags = List.of(new Tag("t1"), new Tag("t2"), new Tag("t3"));
List<Tag> tags2 = List.of(new Tag("t4"), new Tag("t5"));
Article article = new Article();
Article article2 = new Article();
Article article3 = new Article();
Article article4 = new Article();
Article article5 = new Article();
article.setTags(tags);
article3.setTags(tags2);
tags.forEach(entityManager::persist);
tags2.forEach(entityManager::persist);
entityManager.persist(article);
entityManager.persist(article2);
entityManager.persist(article3);
entityManager.persist(article4);
entityManager.persist(article5);
entityManager.flush();
entityManager.clear();
}
@Test
void test() {
Query query = entityManager.createQuery("select a from Article a");
List<Article> tech = query.setMaxResults(20).getResultList();
tech.stream()
.map(ArticleResponseDto::new)
.toList();
}
}
I expected executing queries same in both version, it wasn’t.