单向一对多关联的Criteria Query:基于实体列表查询
嘿,我明白你的问题了——当Person实体没有反向关联到MyPersons时,确实得换个思路用Criteria Query来查询包含特定Person的MyPersons。下面我一步步给你讲怎么实现,不管是匹配单个Person还是多个Person的情况都覆盖到:
1. 匹配单个特定Person的情况
首先最基础的场景:查询包含某一个指定Person的所有MyPersons实体。有两种常用方式:
方式一:直接用isMember检查集合包含
这是最直观的写法,直接判断MyPersons的Person集合是否包含目标实体:
// 获取CriteriaBuilder和查询实例 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<MyPersons> query = cb.createQuery(MyPersons.class); Root<MyPersons> myPersonsRoot = query.from(MyPersons.class); // 你的目标Person实体 Person targetPerson = ...; // 构建查询条件:集合包含目标Person query.select(myPersonsRoot) .where(cb.isMember(targetPerson, myPersonsRoot.get("persons"))); // 执行查询 List<MyPersons> result = entityManager.createQuery(query).getResultList();
方式二:通过Join关联查询
如果需要更灵活的扩展,可以用Join关联Person表,再匹配目标实体:
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<MyPersons> query = cb.createQuery(MyPersons.class); Root<MyPersons> myPersonsRoot = query.from(MyPersons.class); // 关联MyPersons的persons集合(INNER JOIN) Join<MyPersons, Person> personJoin = myPersonsRoot.join("persons", JoinType.INNER); Person targetPerson = ...; // 匹配目标Person,注意加distinct避免重复结果 query.select(myPersonsRoot) .where(cb.equal(personJoin, targetPerson)) .distinct(true); List<MyPersons> result = entityManager.createQuery(query).getResultList();
这里加
distinct(true)是因为Join会让每个匹配的Person对应一条MyPersons记录,去重后才能得到唯一的实体结果。
2. 匹配包含全部指定Person列表的MyPersons
如果你的需求是:查询那些包含目标列表中所有Person的MyPersons实体,就需要用到分组和Having子句:
List<Person> targetPersons = ...; // 你要匹配的Person列表 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<MyPersons> query = cb.createQuery(MyPersons.class); Root<MyPersons> myPersonsRoot = query.from(MyPersons.class); Join<MyPersons, Person> personJoin = myPersonsRoot.join("persons", JoinType.INNER); // 先过滤出关联到列表中任意Person的MyPersons query.where(personJoin.in(targetPersons)) // 按MyPersons分组 .groupBy(myPersonsRoot) // 检查分组内匹配的Person数量等于目标列表大小(确保全部包含) .having(cb.equal(cb.countDistinct(personJoin), targetPersons.size())); List<MyPersons> result = entityManager.createQuery(query).getResultList();
3. 匹配包含任意指定Person列表中元素的MyPersons
如果只要MyPersons包含列表里的任意一个Person就行,写法会更简单:
List<Person> targetPersons = ...; CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<MyPersons> query = cb.createQuery(MyPersons.class); Root<MyPersons> myPersonsRoot = query.from(MyPersons.class); // 用isMemberOfAny直接检查集合是否包含列表中任意元素 query.select(myPersonsRoot) .where(cb.isMemberOfAny(targetPersons, myPersonsRoot.get("persons"))) .distinct(true); List<MyPersons> result = entityManager.createQuery(query).getResultList();
关键注意事项
- 代码中的
"persons"要和你MyPersons实体里的Collection字段名完全一致,别写错了。 - 如果你的Person实体没有正确实现
equals()和hashCode(),用实体直接匹配可能会出错,这时候可以改用Person的主键来匹配:// 示例:用主键匹配单个Person query.where(cb.equal(personJoin.get("id"), targetPerson.getId())); // 示例:用主键列表匹配全部Person List<Long> personIds = targetPersons.stream().map(Person::getId).collect(Collectors.toList()); query.where(personJoin.get("id").in(personIds)) .groupBy(myPersonsRoot) .having(cb.equal(cb.countDistinct(personJoin.get("id")), personIds.size()));
这样应该就能解决你的问题了,要是还有细节没搞清楚,随时补充提问就行~
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

