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?