在 Sub 类 上过滤的 JPA CriteriaBuilder 方法是什么?

What is the JPA CriteriaBuilder way for filtering on Sub Classes?

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

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

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

考虑到鉴别器列似乎超出限制,使用 JPA 标准生成器实现相同目的的推荐方法是什么?

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

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

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

常见查询示例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();

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

但是如果你想要 Criteria API 相当于 Java 的 instanceof 运算符,唯一的方法是显式列出所有子类型 Class 对象。但这会使您的代码在未来的重构等方面变得脆弱。

这是一个实用程序 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);
    }
}