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

为何Criteria API的.not()方法无法正常工作?

问题根源

你写的查询里用了fromProject.joinList("events"),这是内连接——内连接的特性就是只保留两边都有匹配数据的记录,所以这一步已经把所有没有Event的Project过滤掉了。之后你再对这些有Event的Project ID取not(),相当于从已经被筛过的集合里排除它们,结果当然是空的。

正确写法

给你两种靠谱的实现方式,都能准确查出没有关联Event的Project:

方式一:左连接+判断关联为空

用左连接保留所有Project,然后挑出那些没有关联Event的:

public List<Project> findAllWithoutEvents(ProjectFilter filter) {
    Session session = sessionFactory.openSession();
    CriteriaBuilder cb = session.getCriteriaBuilder();
    CriteriaQuery<Project> cr = cb.createQuery(Project.class);
    Root<Project> fromProject = cr.from(Project.class);

    // 左连接events,哪怕没有关联也会保留Project记录
    Join<Project, Event> eventsLeftJoin = fromProject.join("events", JoinType.LEFT);
    cr.select(fromProject)
      .where(cb.isNull(eventsLeftJoin.get("id")))
      .distinct(true); // 去重,避免左连接可能带来的重复数据

    Query<Project> query = session.createQuery(cr);
    return query.getResultList();
}

方式二:NOT EXISTS子查询

通过子查询检查是否存在关联的Event,只保留不存在的Project:

public List<Project> findAllWithoutEvents(ProjectFilter filter) {
    Session session = sessionFactory.openSession();
    CriteriaBuilder cb = session.getCriteriaBuilder();
    CriteriaQuery<Project> cr = cb.createQuery(Project.class);
    Root<Project> fromProject = cr.from(Project.class);

    // 子查询:找和当前Project关联的Event
    Subquery<Long> subquery = cr.subquery(Long.class);
    Root<Event> eventRoot = subquery.from(Event.class);
    subquery.select(eventRoot.get("id"))
            .where(cb.equal(eventRoot.get("project").get("id"), fromProject.get("id")));

    // 筛选没有关联Event的Project
    cr.select(fromProject)
      .where(cb.not(cb.exists(subquery)));

    Query<Project> query = session.createQuery(cr);
    return query.getResultList();
}
额外提示
  • 方式一的distinct(true)最好加上,虽然单纯查无Event的Project时不会有重复,但如果之后加其他关联条件,左连接容易产生重复记录,提前加上更稳妥。
  • 方式二的NOT EXISTS性能通常比NOT IN好,尤其是数据量大的时候,而且不会遇到NOT IN因NULL值导致的异常结果,逻辑更可靠。

内容的提问来源于stack exchange,提问作者Smasher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 12:55:25