ElementCollection上的CriteriaBuilder.isEmpty与JPQL方法

| 我正在尝试使用以下类的JPA2标准API进行简单查询:
// a lot of imports

@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
}
我要查询的内容:查找没有排版的所有内容。 执行此工作的JPQL是:
select t from Thing t where t.typeSet is empty
JPQL查询返回一个预期的结果。条件查询不返回任何结果。
CriteriaBuilder
创建:
SELECT DISTINCT t0.ID, t0.NAME FROM THING t0, TYPES t1 WHERE (((SELECT COUNT(t2.ID) FROM THING t2 WHERE (t1.TYPE_ID = t0.ID)) = 0) **AND (t1.TYPE_ID = t0.ID)**)
最后一个theta-join(标记为**)将全部杀死。而且我不知道为什么表
THING
被指定两次
(THING to, THING t1)
。 显然我做错了。但是我不知道这是怎么回事。     
已邀请:
        我猜问题在于您在Criteria案例中尝试进行显式联接,而在JPQL中则没有。因此,省略联接并执行类似的操作
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实施而言。     

要回复问题请先登录注册