如何在 JPA 2.0 中创建类似“实例”的查询?

问题描述 投票:0回答:3

假设我们有一个抽象@Entity Animal,以及几个扩展 Animal 的实体类,包括 Dog、Cat、Monkey 和 Bat。

如何根据扩展实体的类过滤结果?

示例: 有一些复选框,用户可以选择要检索的实体。

[ ] Dog
[X] Cat
[X] Monkey
[ ] Bat

现在我想使用

Animal
类中定义的(命名)查询来检索实体。我可以在查询中放入什么样的查询参数,以便只返回 Cat 和 Monkey 对象?

java jpa jpa-2.0 jpql
3个回答
33
投票

我不确定它是否受 JPA 支持,但是在 Hibernate 中执行此操作的方法,无论继承策略如何,因此即使您没有鉴别器(或没有将其映射为属性)也是如此使用隐式

class
属性 :

String jpql = "select a from Animal a where a.class in (:classes)";
Query q = em.createQuery(jpql).setParameter("classes", 
                                            Arrays.asList(Cat.class, Monkey.class));

编辑:

我刚刚发现在 JPA2 中可以使用 TYPE 运算符:

String jpql = "SELECT a FROM Animal a WHERE TYPE(a) IN :classes";
Query q = em.createQuery(jpql).setParameter("classes", 
                                            Arrays.asList(Cat.class, Monkey.class));

4
投票

您可以使用鉴别器列和值来仅搜索给定类型的某些子类型。默认情况下,鉴别器列的名称是 JPA 中的 DTYPE,类型是 String,值是类的名称。但是,您可以通过添加类级别注释

@DiscriminatorColumn(name="KIND", discriminatorType=DiscriminatorType.INTEGER)
(对于鉴别器列的名称和类型)和
@DiscriminatorValue("1")
(对于特定类的特定鉴别器值)来覆盖它。然后,您可以在 yoru JPQL 查询的 WHERE 子句中使用它来仅获取某些子类型,例如:
WHERE DTYPE="Dog" OR DTYPE="Cat"


0
投票

这是我使用的:

    /**
     * Build an "instanceof" {@link Predicate} for an entity type.
     */
    @SuppressWarnings("unchecked")
    public static Predicate instanceOf(EntityManager entityManager, Path<?> path, Class<?> type) {
        Preconditions.checkArgument(entityManager != null, "null entityManager");
        Preconditions.checkArgument(path != null, "null path");
        Preconditions.checkArgument(type != null, "null 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);
    }

    /**
     * Build an IN predicate from a collection of possible values.
     */
    public static <T> Predicate in(CriteriaBuilder builder, Expression<T> expr, Iterable<? extends T> values) {
        Preconditions.checkArgument(builder != null, "null builder");
        Preconditions.checkArgument(expr != null, "null expr");
        Preconditions.checkArgument(values != null, "null values");
        final CriteriaBuilder.In<T> in = builder.in(expr);
        values.forEach(in::value);
        return in;
    }
© www.soinside.com 2019 - 2024. All rights reserved.