2 years ago

#61448

test-img

jansohn

CriteriaAPI + subquery creates wrong SQL (invalid identifier)

Not sure what I'm dong wrong so I'm guessing this is a bug. I'm trying to create a simple subquery but Eclipselink produces wrong SQL so the execution fails.

Error message

[EL Warning]: 2022-01-17 17:00:29.258--UnitOfWork(1407952056)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.9.v20200130-0143b822bc): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00904: "T1"."ID"."T1"."ID": invalid identifier

Error Code: 904
Call: SELECT COUNT(t0.ID) FROM Order t0 WHERE t0.OUTPUT IN (SELECT t1.ID.t1.ID FROM Process t1 WHERE (t1.OWNER = ?))
    bind => [0]
Query: ReportQuery(referenceClass=Order sql="SELECT COUNT(t0.ID) FROM Order t0 WHERE t0.OUTPUT IN (SELECT t1.ID.t1.ID FROM Process t1 WHERE (t1.OWNER = ?))")

Sample code

    EntityManager em = ApplicationContextListener.createEntityManager();

    try {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Long> cq = cb.createQuery(Long.class);

        Root<Order> root = cq.from(Order.class);
        cq.select(cb.count(root));

        // Process subquery
        Subquery<Long> sqProcess = cq.subquery(Long.class);
        Root<Process> sqProcessRoot = sqProcess.from(Process.class);
        Path<Long> processId = sqProcessRoot.get("id");

        sqProcess.select(processId)
                .where(cb.equal(sqProcessRoot.get("owner"), cb.parameter(String.class, "person")));

        cq.where(cb.in(root.get("processOutput")).value(sqProcess));

        TypedQuery<Long> tq = em.createQuery(cq);
        int count = tq.setParameter("person", loggedInPerson).getSingleResult().intValue();
        log.debug("SQL count string: {}", tq.unwrap(JpaQuery.class).getDatabaseQuery().getSQLString());
        log.debug("Count = {}", count);
    } finally {
        em.close();
    }

Order

@Entity
@Table(name = "Order")
public class Order implements Serializable {
    private static final long serialVersionUID = 2804475880693788686L;

    @Id
    @SequenceGenerator(name = "ORDER_ID_GENERATOR", sequenceName = "ORDER_SEQ", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDER_ID_GENERATOR")
    private long id;

    // bi-directional many-to-one association to Process
    @ManyToOne
    @JoinColumn(name = "OUTPUT")
    private Process processOutput;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Process getProcessOutput() {
        return this.processOutput;
    }

    public void setProcessOutput(Process processOutput) {
        this.processOutput = processOutput;
    }
}

Process

@Entity
@Table(name = "Process")
public class Process implements Serializable {
    private static final long serialVersionUID = -2021620806203228247L;

    @Id
    @SequenceGenerator(name = "PROCESS_ID_GENERATOR", sequenceName = "PROCESS_SEQ", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PROCESS_ID_GENERATOR")
    @Expose
    private long id;

    @ManyToOne
    @JoinColumn(name = "OWNER")
    private Person owner;

    @XmlTransient
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Person getOwner() {
        return owner;
    }

    public void setOwner(Person owner) {
        this.owner = owner;
    }
}

jpa

eclipselink

jpql

criteria-api

0 Answers

Your Answer

Accepted video resources