有关实体层次结构的JPA2标准查询 [英] JPA2 Criteria queries on entity hierarchy

查看:62
本文介绍了有关实体层次结构的JPA2标准查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我具有以下实体域:

suppose i have the following entity domain:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE")
public abstract class Entity1 {
//some attributes
}

@Entity 
@DiscriminatorValue("T1")
public class Entity2 extends Entity1 {
    @OneToMany(fetch=FetchType.EAGER, cascade = { CascadeType.ALL }, mappedBy="parent")
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Set<Entity1Detail> details = new HashSet<Entity1Detail>();
}

@Entity
public class Entity1Detail {
    @ManyToOne
    @JoinColumn(name="REF")
    private Entity2 parent;

    @Basic
    private Integer quantity;
}

@Entity
@DiscriminatorValue("T2")
public class Entity3 extends Entity1 {
//some other attributes
}

当我执行JPQL查询时:

when i do a JPQL query:

select e from Entity1 e left join e.details d where d.quantity > 1

它运行良好(左联接; P).但是,当我尝试使用JPA2标准API构建相同的查询时:

it runs well (left join ;P). however when i try to construct the same query using JPA2 Criteria API:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery q = builder.createQuery();
Root r = q.from(Entity1.class);
q.select(r);
q.where(builder.gt(r.join("details", JoinType.LEFT).get("quantity"), 1));

我在"join"中获得了NPE,因为属性"details"不属于Entity1(实际上是正确的,我必须在Entity2.class上进行选择).事实是,当我不得不使用Criteria API构造动态查询时,我对层次结构一无所知,我只是通过了一个类.

i get NPE in "join" because the attribute "details" doesn't belong to Entity1 (which is actually true, i have to select on Entity2.class instead). the thing is that when i have to construct my dynamic query using Criteria API i don't really know anything about hierarchy, i'm just passed a Class.

我知道Criteria API都是类型安全的,但是有没有办法解决此问题?可能带有别名(就像我之前使用Hibernate Criteria API一样,遍历带有别名的联接):

i understand that Criteria API is typesafe and all that, but is there a way to work around this? with aliases maybe (as before i used Hibernate Criteria API, traversing joins with aliases):

Criteria c = session.createCriteria(Entity1.class);
c.createAlias("details", "d");
c.add(Restrictions.ge("d.quantity", 1));

推荐答案

您需要基于entity2.details进行查询.由于标准API是类型安全的,因此它可以捕获到object1没有名为"details"的字段

You need to base your query on entity2.details. Since the criteria API is type-safe, it catches that entity1 has no field named "details"

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery q = builder.createQuery();
Root r = q.from(Entity2.class);    // Must use subclass as root
q.select(r);
q.where(builder.gt(r.join("details", JoinType.LEFT).get("quantity"), 1));

由于Entity2扩展了Entity1,因此您可以安全地将结果强制转换为父类型.例如:

Since Entity2 extends Entity1, you can cast your results as the parent type safely. For example:

CriteriaQuery<Entity1> q = builder.createQuery(Entity1.class);
Root r = q.from(Entity2.class);    // Must use subclass as root

将返回Entity1的列表

will return a list of Entity1

CriteriaQuery<Entity2> q = builder.createQuery(Entity2.class);
Root r = q.from(Entity2.class);    // Must use subclass as root

将返回Entity2的列表

will return a list of Entity2

我想我误解了这里的目标.如果您希望所有的Entity1都是Entity2,且其details.quantity< == 1,则您需要做更多的事情.

I think I misunderstood the goal here. If you want all Entity1 UNLESS they are Entity2 with details.quantity <= 1, you need to do more.

您不能使用从Entity1Detail到Entity1的左连接,因为严格来说这不是类型安全的.相反,您需要以某种方式将Entity2连接到Entity1Detail.可能在这里使用的最佳工具是相关子查询.

You can't use a left join from Entity1Detail to Entity1, because that is not strictly type safe. Instead, you need to join Entity2 to Entity1Detail somehow. Probably the best tool to use here is a correlated subquery.

CriteriaQuery<Entity1> q = builder.createQuery(Entity1.class);
Root<Entity1> ent1 = q.from(Entity1.class);

SubQuery<Entity2> subq = q.subquery(Entity2.class);
Root<Entity2> ent2 = subq.from(Entity2.class);
Path<Integer> quantity = ent2.join("details", JoinType.LEFT).get("quantity");
Predicate lessThan = builder.lte(quantity,1);
Predicate correlatedSubqJoin = cb.equal(ent1,ent2)
subq.where(lessThan, correlatedSubqJoin);

q.select(ent1);
q.where(builder.exists(subq).not());

条件API不知道您是单表继承,因此您必须为所有继承策略(包括Joined继承策略)编写查询.

The criteria API does not know that you are single table inheritance, so you have to write your queries for all inheritance strategies, including a Joined inheritance strategy.

这篇关于有关实体层次结构的JPA2标准查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆