ElementCollection 与 JPQL 方法上的 CriteriaBuilder.isEmpty

发布于 2024-11-15 10:55:37 字数 2574 浏览 2 评论 0原文

我正在尝试使用 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 isempty

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)

显然我做错了。但我不知道出了什么问题。

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

// 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
}

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

The JPQL which does the job is:

select t from Thing t where t.typeSet is empty

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

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)**)

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白色秋天 2024-11-22 10:55:37

我猜问题是您试图在 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 实现来说是这样。

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)));

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文