为什么 CriteriaQuery 上的 left join 不过滤结果?

Why left join on CriteriaQuery doesn't filter results?

我有两个实体,UserRoles,每个实体都具有活动布尔参数和 ManyToMany 关系。

此布尔参数用于逻辑删除。

为什么我 运行 下面的查询结果中包含非活动角色?

 CriteriaBuilder builder = em.getCriteriaBuilder();
 CriteriaQuery<User> query = builder.createQuery(User.class);

 //Select
 Root<User> user = query.from(User.class);

 //Join
 SetJoin<User, Role> role = user.joinSet("roles", JoinType.LEFT);
 Predicate rolesActivePredicate = builder.isTrue(role.get("active"));
 role.on(rolesActivePredicate);

 query.multiselect(user).distinct(true);

 //Where
 Predicate usernamePredicate = builder.equal(user.get("username"), username);
 Predicate activePredicate = builder.isTrue(user.get("active"));
 query.where(usernamePredicate, activePredicate);

 TypedQuery<UnikUser> typedQuery = em.createQuery(query);
 return Optional.of(typedQuery.getSingleResult());
  1. 考虑以下 UserRole@OneToMany 关系。
 User-1 : Active-Role-1, Active-Role-2, In-Active-Role-3
 User-2 : In-Active-Role-3
 User-3 : Active-Role-1, Active-Role-2
  1. JPA 首先找到 User 条满足您条件的记录(至少有一个活跃的角色)
 User-1
 User-3
  1. 这里就是你where条件的作用结束。一旦决定要获取哪个记录 ID,JPA 将完整获取那些 User 记录。 User-1User-3 及其所有相关角色(包括非活动角色)。它可能会 join 或另一个 select 但无论何时,它都会获取所有相关字段

  2. 总而言之,一旦它决定获取 entity它就不能对其相关字段进行任何过滤。在这种情况下,您希望在 user.getRoles() 中过滤对象,但它不能。

  3. 如果 JPA 允许这样做,它就不能执行 dirty checkingcascadingrepeatable read。所以它不允许