假设我具有以下实体域:
@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
}
Run Code Online (Sandbox Code Playgroud)
当我执行JPQL查询时:
select e from Entity1 e left join e.details d where d.quantity > 1
Run Code Online (Sandbox Code Playgroud)
它运行良好(左联接; P)。但是,当我尝试使用JPA2标准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));
Run Code Online (Sandbox Code Playgroud)
我在“ join”中得到NPE,因为属性“ details”不属于Entity1(实际上是正确的,我必须在Entity2.class上进行选择)。事实是,当我不得不使用Criteria API构建动态查询时,我对分层结构一无所知,我只是通过了一个类。
我知道Criteria API都是类型安全的,但是有办法解决此问题吗?可能带有别名(与我之前使用Hibernate Criteria API一样,遍历带有别名的联接):
Criteria c = session.createCriteria(Entity1.class);
c.createAlias("details", "d");
c.add(Restrictions.ge("d.quantity", 1));
Run Code Online (Sandbox Code Playgroud)
您需要基于entity2.details. 由于标准 API 是类型安全的,它捕获到 entity1 没有名为“详细信息”的字段
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));
Run Code Online (Sandbox Code Playgroud)
由于 Entity2 扩展了 Entity1,您可以安全地将结果转换为父类型。例如:
CriteriaQuery<Entity1> q = builder.createQuery(Entity1.class);
Root r = q.from(Entity2.class); // Must use subclass as root
Run Code Online (Sandbox Code Playgroud)
将返回 Entity1 的列表
CriteriaQuery<Entity2> q = builder.createQuery(Entity2.class);
Root r = q.from(Entity2.class); // Must use subclass as root
Run Code Online (Sandbox Code Playgroud)
将返回 Entity2 的列表
编辑:
我想我误解了这里的目标。如果您想要所有 Entity1,除非它们是具有 details.quantity <= 1 的 Entity2,您需要做更多。
您不能使用从 Entity1Detail 到 Entity1 的左连接,因为这不是严格类型安全的。相反,您需要以某种方式将 Entity2 加入 Entity1Detail。此处使用的最佳工具可能是相关子查询。
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());
Run Code Online (Sandbox Code Playgroud)
Criteria API 不知道您是单表继承,因此您必须为所有继承策略编写查询,包括 Joined 继承策略。
| 归档时间: |
|
| 查看次数: |
17450 次 |
| 最近记录: |