You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单向一对多关联的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:42:51