如何从关联的ManyToMany表中查询指定分类的Item列表?
问题背景
存在两个通过@ManyToMany关联的JPA实体:
Category实体
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Entity public class Category { @Id @GeneratedValue(generator = Constants.ID_GENERATOR) protected Long id; protected String code; @ManyToMany(CascadeType.PERSIST) @JoinTable( name = "CATEGORY_ITEM", joinColumns = @JoinColumn(name = "CATEGORY_ID"), inverseJoinColumns = @JoinColumn(name = "ITEM_ID") ) protected Set<Item> items = new HashSet<Item>(); @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Category category = (Category) o; return Objects.equals(code, category.code); } @Override public int hashCode() { return Objects.hash(code); } }
Item实体
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Entity public class Item { @Id @GeneratedValue(generator = Constants.ID_GENERATOR) protected Long id; protected String code; @ManyToMany(mappedBy = "items") protected Set<Category> categories = new HashSet<Category>(); @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Item item = (Item) o; return Objects.equals(code, item.code); } @Override public int hashCode() { return Objects.hash(code); } }
尝试通过JPQL获取指定code的分类下所有Item时,所有查询均返回空列表,但直接通过ID查询Category实体后,能正常获取关联的Item集合:
Category category = categoryRepository.findById(1L).orElseThrow(); assertEquals(category.getItems().size(), 2);
问题根源
所有JPQL查询返回空的原因是:查询语句中使用了西里尔字母с(俄语小写c)代替了英文小写字母c,例如第一个查询中的join с.items i,JPA无法识别这个错误的别名,导致查询逻辑失效。
正确的查询写法
以下是几种可行的正确JPQL查询:
1. CategoryRepository中的关联查询
@Query("select i from Category c join c.items i where c.code = :code") List<Item> findItemsWithCode(@Param("code") String code);
如果需要避免重复(当Item属于多个分类时),可以添加distinct:
@Query("select distinct i from Category c join c.items i where c.code = :code") List<Item> findItemsWithCode(@Param("code") String code);
2. CategoryRepository中直接查询关联集合
@Query("select c.items from Category c where c.code = :code") List<Item> findItemsWithCode(@Param("code") String code);
3. ItemRepository中的反向关联查询
@Query("select i from Item i join i.categories c where c.code = :code") List<Item> findItemsWithCode(@Param("code") String code);
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

