2

My task is to migrate a dynamic search query from sql to jpa criteria api. The query returns informations about tasks that are collected from various associated entities. In a simplified form the classes look like this:

@Entity
@Table(name = "TASKS")
public class Task {
    private AbstractPayload payload;
}

@Entity
@Table(name = "TASK_PAYLOAD")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class AbstractPayload {
    // Id and other stuff
}

@Entity(name = "PayloadSubtype")
@DiscriminatorValue("2")
public class PayloadSubtype {
    @Column(name = "MOST_RECENT_RESPONSE_DATE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastResponseDate;
}

The query should issue only one statement. My first aproach looked like this:

CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> taskQuery = criteriaBuilder.createTupleQuery();
Root<Task> task = taskQuery.from(Task.class);
Join<Task, AbstractPayload> payload = task.join(Task_.payload);
CriteriaQuery<Tuple> multiselect = taskQuery.multiselect(
    payload.get(PayloadSubtype_.lastResponseDate);

In the last line payload.get raises a compile error: "The method get(SingularAttribute) in the type Path is not applicable for the arguments (SingularAttribute)"

Understandable as AbstractPayload has no attribute lastResponseDate at least from an OO perspective.

I found several questions and answers that propose to use subtype-specific subqueries. But the problem here is that subqueries can´t be used with tuple queries.

I tried something like this to build a subquery:

Subquery<PayloadSubtype> specificSubquery = taskQuery.subquery(PayloadSubtype.class);
Root<PayloadSubtype> payloadSubtype = specificSubquery.from(PayloadSubtype.class);
payloadSubtype.alias("payloadSubtype");
Root<Task> taskCorrelation = specificSubquery.correlate(task);
Path<AbstractPayload> taskPayload = taskCorrelation.get(Task_.payload);
Path<Long> payloadId = reviewNonResponderPayload.get(AbstractPayload_.id);
reviewNonResponderSubquery
        .select(payloadSubtype)
        .where(criteriaBuilder.equal(taskPayload, payloadId));

CriteriaQuery<Tuple> multiselect = taskQuery
    .multiselect(
        payloadSubtype.get(PayloadSubtype_.lastResponseDate));

This code compiles, but throws an exception at runtime: Invalid path: 'payloadSubtype.lastResponseDate'

or if I ommit the alias: Invalid path: 'generatedAlias3.lastResponseDate'

Does anybody know how this can be acomplished with JPA Criteria or if this is impossible at all?

4

0 回答 0