I'm trying to implement a EntityGraph with Data-JPA, since using QueryDslPredicateExecutor<T>
exposes the method findAll(Predicate, Pageable)
the one I need, I tried to override it to annotate with @EntityGraph
then the troubles began it's throwing :
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=appointment,role=com.physioclinic.entity.Appointment.createdBy,tableName=user,tableAlias=user5_,origin=appointment appointmen0_,columns={appointmen0_.createdBy_id ,className=com.physioclinic.entity.User}}] [select count(appointment)
from com.physioclinic.entity.Appointment appointment where lower(concat(concat(appointment.patient.person.name,?1),appointment.patient.person.surname)) like ?2 escape '!']; nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=appointment,role=com.physioclinic.entity.Appointment.createdBy,tableName=user,tableAlias=user5_,origin=appointment appointmen0_,columns={appointmen0_.createdBy_id ,className=com.physioclinic.entity.User}}]
When I use the default method the way it's comes nothing bad happens, even using the same Predicate
, but I can't use EntityGraph, Is there some problem with my implementation or with the Predicate?
Follows the objects in the scenario:
Entity
@Table(name = "appointment")
@Entity
@Getter
@Setter
@NamedEntityGraphs({@NamedEntityGraph(name = "graph.Appointment.default", includeAllAttributes = true,
attributeNodes = {@NamedAttributeNode(value = "physiotherapist"),
@NamedAttributeNode(value = "patient"),
@NamedAttributeNode(value = "care")})})
public class Appointment extends PersistableAuditable<User, Long> {
private static final long serialVersionUID = -4325126792470516159L;
@DateTimeFormat(pattern = "dd/MM/yyyy")
@NotNull
@Column(name = "date")
private LocalDate date;
@DateTimeFormat(pattern = "HH:mm")
@NotNull
@Column(name = "schedule")
private LocalTime schedule;
@ManyToOne
@JoinColumn(name = "physiotherapist", referencedColumnName = "id")
private Physiotherapist physiotherapist;
@ManyToOne
@JoinColumn(name = "service", referencedColumnName = "id")
private Service service;
@ManyToOne
@JoinColumn(name = "patient", referencedColumnName = "id")
private Patient patient;
@ManyToOne(cascade = CascadeType.REMOVE)
@JoinColumn(name = "care", referencedColumnName = "id")
private Care care;
public Appointment(long id) {
setId(id);
}
public Appointment() {
}
/**
* Helpers
*/
public boolean isSpecialPrice() {
return care.getPrivateCare() && care.getSpecial() && care.getSpecialPrice() != null;
}
public boolean isPrivatePrice() {
return care.getPrivateCare() && care.getHealthCare() == null;
}
public boolean isHealthCarePrice() {
return !care.getPrivateCare() && care.getHealthCare() != null;
}
}
Repository
public interface AppointmentRepository extends JpaRepository<Appointment, Long>,
QueryDslPredicateExecutor<Appointment> {
@EntityGraph(value = "graph.Appointment.default")
Page<Appointment> findAll(Predicate predicate, Pageable pageable);
}
Predicate
public final class AppointmentPredicate {
private AppointmentPredicate() {
}
public static Predicate bySearch(String search) {
QPerson person = QAppointment.appointment.patient.person;
return person.name.concat(" ").concat(person.surname).containsIgnoreCase(search);
}
}
I've faced with exactly the same problem and had a lot of fun debugging the spring source code. So the root cause is: spring is applying hints on the count query which leads to that error.
QueryDslJpaRepository.java:
And the workaround is: create a supporting interface to your repository interface and implement it overriding the query creation logic. Here is my midnight implementation (it is just a prototype which must be improved of course).
Looks like it is a bug and I'm going to submit it to the spring jpa jira.