CriteriaBuilder.isEmpty上ElementCollection与JPQL方法 [英] CriteriaBuilder.isEmpty on an ElementCollection vs. JPQL approach

查看:2599
本文介绍了CriteriaBuilder.isEmpty上ElementCollection与JPQL方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用在下面的类(ES)的JPA2标准API做一个简单的查询:

I'm trying to do a simple query using the JPA2 criteria API on the following class(es):

//大量进口

@Entity
公共类事情{
    枚举类型{FIRST,SECOND,THIRD};

@Entity public class Thing { enum Type { FIRST, SECOND, THIRD };

@SequenceGenerator(name = "Thing_SeqGen", sequenceName = "Thing_Id_Seq", initialValue = 1000)
@Id
@GeneratedValue(generator = "Thing_SeqGen")
private int id;

private String name = "name";

@Enumerated(EnumType.STRING)
@ElementCollection(targetClass = Thing.Type.class)
@CollectionTable(name = "TYPES", joinColumns = { @JoinColumn(referencedColumnName = "ID", name = "TYPE_ID") })

private Set<Thing.Type> typeSet = new HashSet<Thing.Type>();
public static void main(final String[] args) {
    new Thing().start();
}

public void start() {
    final Thing firstThing = new Thing();
    firstThing.setName("First one");
    firstThing.setTypeSet(EnumSet.of(Thing.Type.FIRST));
    final Thing firstAndSecondThing = new Thing();
    firstAndSecondThing.setName("Test2");
    firstAndSecondThing.setTypeSet(EnumSet.of(Thing.Type.FIRST, Thing.Type.SECOND));
    final Thing bareThing = new Thing();
    bareThing.setName("Test3");

    final EntityManagerFactory emf =  Persistence.createEntityManagerFactory("sandbox");
    final EntityManager em = emf.createEntityManager();

    em.getTransaction().begin();
    em.persist(firstThing);
    em.persist(firstAndSecondThing);
    em.persist(bareThing);
    em.getTransaction().commit();

    em.getTransaction().begin();
    final CriteriaBuilder cb = em.getCriteriaBuilder();
    final CriteriaQuery<Thing> c = cb.createQuery(Thing.class);
    final Root<Thing> root = c.from(Thing.class);
    final Join<Thing, Set<Thing.Type>> typeJoin = root.join("typeSet");

    c.select(root).distinct(true).where(cb.isEmpty(typeJoin));

    final List<Thing> results = em.createQuery(c).getResultList();

    em.getTransaction().commit();
}

// getter/setter methods omitted

}

我要查询什么:找到它没有排版所有的事情

What I want to query: Find all things which has no typeset.

由它来完成作业的JPQL是:

The JPQL which does the job is:

从事情t选择t其中t.typeSet为空

该JPQL查询返回一个结果预计。
条件查询到任何结果。
在SQL中的CriteriaBuilder创建:

The JPQL query returns one result which is expected. The criteria query returns no results. The SQL the CriteriaBuilder created:

SELECT DISTINCT t0.ID,t0.NAME FROM THING T0,T1类型WHERE(((SELECT COUNT(t2.ID)FROM THING T2 WHERE(t1.TYPE_ID = t0.ID))= 0)** AND(t1.TYPE_ID = t0.ID)**)

最后的论旨加入(标记**)杀死了这一切。我不知道为什么被指定的表THING两次(事,物T1)。
很显然,我做错了。但是我不知道什么是错。

The last theta-join (marked **) kills it all. And I have no idea why the table THING is specified twice (THING to, THING t1). Obviously I'm doing wrong. But I have no clue what's the fault.

任何暗示和/或帮助是非常AP preciated。

Any hint and/or help is highly appreciated.

推荐答案

我猜问题是,你正在试图做的情况下,标准明确的加盟,而在JPQL你不知道。所以省略了加入和做一些像

I'd guess the problem is that you're trying to do an explicit join in the Criteria case, whereas in the JPQL you don't. So omit the join and do something like

Metamodel model = emf.getMetamodel();
ManagedType thingType = model.managedType(Thing.class);
CollectionAttribute typeSetAttr = thingType.getCollection("typeSet");
c.select(root).distinct(true).where(cb.isEmpty(root.get(typeSetAttr)));

这应该然后转换成相同的JPQL为您发布...或者至少它为DataNucleus的JPA实现。

This should then translate into the same JPQL as you posted ... or at least it does for DataNucleus JPA implementation.

这篇关于CriteriaBuilder.isEmpty上ElementCollection与JPQL方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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