Hibernate多对多关联:如何用CriteriaQuery查询指定Content的所有Document
嘿,我来帮你搞定Hibernate多对多关联下用CriteriaQuery查询关联文档的问题!首先咱们得先明确实体类的多对多配置,然后再写查询逻辑,一步一步来:
第一步:确认多对多实体配置
首先假设你的两个实体Content和Document是双向多对多关联,中间表比如叫content_document,实体类大概是这样的:
Content实体
@Entity public class Content { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 其他业务字段,比如标题、内容等... @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "content_document", // 中间表名称 joinColumns = @JoinColumn(name = "content_id"), // Content在中间表的外键 inverseJoinColumns = @JoinColumn(name = "document_id") // Document在中间表的外键 ) private Set<Document> documents = new HashSet<>(); // 别忘了getter和setter }
Document实体
@Entity public class Document { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 其他业务字段,比如文件名、路径等... // 这里用mappedBy指定关联关系由Content端维护 @ManyToMany(mappedBy = "documents", fetch = FetchType.LAZY) private Set<Content> contents = new HashSet<>(); // getter和setter }
第二步:用CriteriaQuery查询指定Content关联的所有Document
这里有两种常见的写法,本质都是通过关联查询过滤,你可以选自己习惯的:
写法一:从Content出发关联到Document
这种方式以Content为根实体,关联到它的documents集合,然后过滤出目标Content的关联文档:
// 假设你要查询的Content的ID是这个值 Long targetContentId = 123L; // 获取EntityManager(根据你的项目环境,比如Spring里可以@Autowired注入) EntityManager em = ...; // 创建CriteriaBuilder和CriteriaQuery CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Document> query = cb.createQuery(Document.class); // 从Content表作为查询根 Root<Content> contentRoot = query.from(Content.class); // 关联到Content的documents集合 Join<Content, Document> documentJoin = contentRoot.join("documents"); // 如果你用JPA元模型,也可以写Content_.documents,更类型安全 // 添加过滤条件:只查ID等于targetContentId的Content关联的Document query.where(cb.equal(contentRoot.get("id"), targetContentId)); // 一定要加distinct!因为多对多关联查询会产生笛卡尔积,导致重复的Document实例 query.distinct(true); // 执行查询,得到结果列表 List<Document> associatedDocuments = em.createQuery(query).getResultList();
写法二:从Document出发关联到Content
这种方式反过来,以Document为根实体,关联到它的contents集合,过滤出关联了目标Content的Document:
Long targetContentId = 123L; EntityManager em = ...; CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Document> query = cb.createQuery(Document.class); Root<Document> docRoot = query.from(Document.class); // 关联到Document的contents集合 Join<Document, Content> contentJoin = docRoot.join("contents"); // 过滤条件:关联的Content的ID等于目标ID query.where(cb.equal(contentJoin.get("id"), targetContentId)); // 同样要加distinct去重 query.distinct(true); List<Document> associatedDocuments = em.createQuery(query).getResultList();
关键注意点
- 必须加
distinct(true):多对多关联在执行JOIN查询时会生成笛卡尔积,同一个Document可能会被多次返回,用distinct可以确保结果里每个Document只出现一次。 - 元模型的使用:如果你的项目生成了JPA元模型(就是那些带下划线的类,比如
Content_、Document_),推荐用它们来代替字符串属性名,这样能避免拼写错误,还能享受编译时类型检查。 - 懒加载的影响:这里查询出来的
Document实例是已经初始化好的,因为我们是直接查询并返回Document,不需要额外处理懒加载问题。
内容的提问来源于stack exchange,提问作者Marco Antonio Mota
相关产品推荐
相关产品推荐

