2014-12-15 11 views
6

Sto cercando di implementare un EntityGraph con Data-JPA, dal momento che utilizzando QueryDslPredicateExecutor<T> espone il metodo findAll(Predicate, Pageable) quello che ho bisogno, ho cercato di ignorare ad annotare con @EntityGraph poi i guai cominciarono sta lanciando:Overriding Primavera-Data-JPA metodo predefinito annotazione con EntityGraph provoca QueryException

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

Quando uso il metodo di default il modo in cui è viene nulla di male accade, anche utilizzando lo stesso Predicate, ma non posso usare EntityGraph, c'è qualche problema con la mia realizzazione o con il predicato?

Segue gli oggetti dello 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); 
} 

predicato

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

} 
+0

Dove è possibile trovare una soluzione? Avere lo stesso problema. – bjoernhaeuser

+0

Purtroppo non sono riuscito a trovare una soluzione, quindi l'ho lasciato in default –

risposta

5

che ho affrontato con esattamente lo stesso problema e aveva Un sacco di divertimento nel debugging del codice sorgente di primavera. Quindi la causa principale è: molla sta applicando suggerimenti sulla query di conteggio che porta a quell'errore.

QueryDslJpaRepository.java:

@Override 
public Page<T> findAll(Predicate predicate, Pageable pageable) { 

    JPQLQuery countQuery = createQuery(predicate); 
    JPQLQuery query = querydsl.applyPagination(pageable, createQuery(predicate)); 
.... 
} 

protected JPQLQuery createQuery(Predicate... predicate) { 

    JPAQuery query = querydsl.createQuery(path).where(predicate); 
    CrudMethodMetadata metadata = getRepositoryMethodMetadata(); 

    if (metadata == null) { 
     return query; 
    } 

    LockModeType type = metadata.getLockModeType(); 
    query = type == null ? query : query.setLockMode(type); 

    for (Entry<String, Object> hint : getQueryHints().entrySet()) { 
     query.setHint(hint.getKey(), hint.getValue()); 
    } 

    return query; 
} 

E la soluzione è: creare un'interfaccia di supporto per l'interfaccia repository e attuare esso ignorando la logica di creazione di query. Ecco la mia implementazione di mezzanotte (è solo un prototipo che ovviamente deve essere migliorato).

public interface SomeRepository extends JpaRepository<SomeEntity, Long>, QueryDslPredicateExecutor<SomeEntity>, SomeRepositoryCustom { 
} 


public interface SomeRepositoryCustom { 
    Page<SomeEntity> findAll(Predicate predicate, Pageable pageable); 
} 

public class SomeRepositoryImpl extends SimpleJpaRepository<SomeEntity, Long> 
    implements SomeEntityRepositoryCustom 
{ 
    private final EntityManager entityManager; 
    private final EntityPath<SomeEntity> path; 
    private final PathBuilder<SomeEntity> builder; 
    private final Querydsl querydsl; 

    @Autowired 
    public SomeRepositoryImpl(EntityManager entityManager) { 
     super(SomeEntity.class, entityManager); 


     CrudMethodMetadata metadata = getRepositoryMethodMetadata(); 
     this.entityManager = entityManager; 
     this.path = SimpleEntityPathResolver.INSTANCE.createPath(SomeEntity.class); 
     this.builder = new PathBuilder<>(path.getType(), path.getMetadata()); 
     this.querydsl = new Querydsl(entityManager, builder); 
    } 

    @Override 
    public Page<SomeEntity> findAll(Predicate predicate, Pageable pageable) { 
     JPAQuery countQuery = createQuery(predicate); 
     JPAQuery query = (JPAQuery) querydsl.applyPagination(pageable, createQuery(predicate)); 

     query.setHint(EntityGraph.EntityGraphType.LOAD.getKey(), 
      entityManager.getEntityGraph("YOUR GRAPH KEY")); 

     Long total = countQuery.count(); 
     List<SomeEntity> content = total > pageable.getOffset() ? query.list(path) : 
      Collections.<SomeEntity> emptyList(); 

     return new PageImpl<>(content, pageable, total); 
    } 

    private JPAQuery createQuery(Predicate predicate) { 
     return querydsl.createQuery(path).where(predicate); 
    } 

} 

Sembra che sia un bug e ho intenzione di inviarlo alla jpa jira di primavera.

+0

Grazie mille per aver condiviso questo, darò un'occhiata e salverò per i prossimi progetti! –

Problemi correlati