Hibernate Criteria API @ElementCollection 上的子查询

Hibernate Criteria API Subquery on @ElementCollection

我已经搜索了很多,但无法正常工作。 我也发现了这个,它很接近但是它需要一个不必要的连接并且不能忽略区分大小写:

这是简化的实体:

@Entity(name = "Users")
public class User {
    @Id
    @Column(columnDefinition = "TEXT")
    private String id;

    @ElementCollection
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<String> communities;
}

jpa/hibernate 魔术将其转换为两个表:users(text id)users_communities(text id, text communities )

我想映射到条件的普通 sql 语句是:

select u.id from users u
   where u.users_id not in (
    select uc.users_id
    from users_communities uc
    where lower(communities) = 'test_user_app'
);

这是我当前的 java 代码。如何在 subJoin 上使用“criteriaBuilder.lower()”?没有更简单的方法吗?是否可以避免手动 subJoin?

Subquery<String> subquery = criteria.subquery(String.class);
Root<User> subRoot = subquery.from(User.class);
Join<Object, Object> subJoin = subRoot.join("communities");
subquery.select(subRoot.get("id"));
subquery.where(criteriaBuilder.equal(root.get("id"), subRoot.get("id")), subJoin.in("community_to_find"));
return criteriaBuilder.exists(subquery);

令人难以置信,花了我一整天...... 如果不需要不区分大小写或类似表达式,最简单的方法是:

criteriaBuilder.isMember(
   "community_to_find", 
   criteria.from(User.class).get("communities")
); 

万一确实需要类似的表达式或不区分大小写: 目前似乎无法避免不必要的子连接!无论如何,这终于让我的测试再次变绿了 :-) :

Subquery<String> subquery = criteria.subquery(String.class);
Root<User> subRoot = subquery.from(User.class);
subquery.select(subRoot.get("id"));
subquery.where(criteriaBuilder.like(criteriaBuilder.lower(subRoot.join("communities")), argument));
return criteriaBuilder.in(root.get("id")).value(subquery);

         

提示: 您可能已经从外部查询定义了 Root,因为它是一个 ElementCollection,所以很可能是相同的 class。 在这种情况下,您可以通过以下方式定义更通用的 subRoot:

Root<? extends User> subRoot = subquery.from(root.getJavaType());