在 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);
}
}
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);
}
}