用于过滤子类的JPA CriteriaBuilder方法是什么?

时间:2016-04-04 09:00:35

标签: java jpa criteria-api

JPA 2.0提供了一种使用JPQL表达式TYPE按子类进行过滤的方法,例如:

SELECT e
FROM entity e
WHERE TYPE(e) = :entityType

其中,参数entityType是鉴别器列的值。

考虑到鉴别器列似乎不受限制,建议使用JPA标准构建器实现相同的方法是什么?

我使用的是JPA 2.1,到目前为止唯一能够将鉴别器列映射为Java实体中的只读字段的解决方案,但我不确定这是否是受支持的功能。

3 个答案:

答案 0 :(得分:7)

常见查询示例are here

示例:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root e = cq.from(Entity.class);
cq.where(cb.equal(e.type(), entityType));
Query query = em.createQuery(cq);
List<Entity> result = query.getResultList();

答案 1 :(得分:2)

您可以使用路径类型方法as documented here

Predicate p = cb.equal(e.type(), cb.literal(Entity.class));

答案 2 :(得分:0)

如果您只想检查表达式的 exact 类型,请如上所述使用Path.type()

但是,如果您想要与Java的instanceof运算符等效的Criteria API,唯一的方法是显式列出所有子类型Class对象。但这会使您的代码不易将来进行重构等。

这是一个提供了JPAUtil.instanceOf()方法的实用程序类,可以解决该问题:

/**
 * JPA utility methods.
 */
public final class JPAUtil {

    private JPAUtil() {
    }

    /**
     * Build an IN predicate from a collection of possible values.
     */
    public static <T> Predicate in(CriteriaBuilder builder, Expression<T> expr, Iterable<? extends T> values) {
        final CriteriaBuilder.In<T> in = builder.in(expr);
        values.forEach(in::value);
        return in;
    }

    /**
     * Build an "instanceof" predicate.
     */
    @SuppressWarnings("unchecked")
    public static Predicate instanceOf(EntityManager entityManager, Path<?> path, Class<?> type) {
        final Set<Class<?>> subtypes = entityManager.getMetamodel().getManagedTypes().stream()
          .map(ManagedType::getJavaType)
          .filter(type::isAssignableFrom)
          .collect(Collectors.toSet());
        return JPAUtil.in(entityManager.getCriteriaBuilder(), (Expression<Class<?>>)path.type(), subtypes);
    }
}