JPA request problem : Validation failed for query for method public abstract java.util.List

Xifly :

I've a problem with my JPA request. I work on a spring project with spring MVC, spring data on a TomCat server.

I've these tables :

Tables

I need, starting from the ID of a document, to find the questions and answers related to it. It's something like that in SQL :

Select * from quizz_question, quizz_answer
where quizz_question.id = ( Select question_id from document_question Where document_id = 4406585 )
and quizz_answer.question_ID = quizz_question.id 

My Document and QuizzQuestion entities are joined using the DOCUMENT_QUESTION table.

Document entity :

@Entity
@Table(name = TAB_DOCUMENT)
public class Document implements Serializable, IEntity<Long> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Long id;

    @Column(name = "CONTENT")
    @Lob
    private String content;

    @ManyToMany(fetch = FetchType.EAGER,cascade = {CascadeType.MERGE,CascadeType.REMOVE})
    @JoinTable(name = SopraTableConstants.TAB_DOCUMENT_QUESTION, 
        uniqueConstraints = { @UniqueConstraint(name = SopraTableConstants.CONSTRAINT_UK_DOCUMENT_QUESTION, columnNames = {"DOCUMENT_ID","QUESTION_ID"}) }, 
        joinColumns = { @JoinColumn(name = "DOCUMENT_ID", referencedColumnName = "ID") }, 
        inverseJoinColumns = { @JoinColumn(name = "QUESTION_ID", referencedColumnName = "ID") }
    )
    @SortNatural
    private SortedSet<QuizzQuestion> questions=new TreeSet<QuizzQuestion>();

    /** @return the content */
    public String getContent() {
        return content;
    }

    /** @return the questions */
    public SortedSet<QuizzQuestion> getQuestions() {
        return questions;
    }

    /** @param questions
     *            the questions to set */
    public void setQuestions(final SortedSet<QuizzQuestion> questions) {
        this.questions=questions;
    }
}

QuizzQuestion entity :

@Entity
@Table(name = TAB_QUIZZ_QUESTION)
public class QuizzQuestion implements Serializable, IEntity<Long>, Comparable<QuizzQuestion> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String questionLabel;

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
    @JoinColumn(name = "QUESTION_ID", referencedColumnName = "id", foreignKey = @ForeignKey(name =  SopraTableConstants.FK_QUIZZ_ANSWER_QUIZZ_DOCUMENT))
    @SortNatural
    private SortedSet<QuizzAnswer> answers;

    @OneToOne
    @JoinColumn(name = "QUIZZ_ANSWER_id", referencedColumnName = "id", foreignKey = @ForeignKey(name =  SopraTableConstants.FK_QUIZZ_RIGHT_ANSWER))
    private QuizzAnswer rightAnswer;

    public SortedSet<QuizzAnswer> getAnswers() {
        return answers;
    }

    @Override
    public Long getId() {
        return id;
    }

    public String getQuestionLabel() {
        return questionLabel;
    }

    public QuizzAnswer getRightAnswer() {
        return rightAnswer;
    }

    public void setAnswers(SortedSet<QuizzAnswer> param) {
        this.answers = param;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }

    public void setQuestionLabel(String param) {
        this.questionLabel = param;
    }

    public void setRightAnswer(QuizzAnswer param) {
        this.rightAnswer = param;
    }
}

QuizzAnswer entity :

@Entity
@Table(name = TAB_QUIZZ_ANSWER)
public class QuizzAnswer implements Serializable, IEntity<Long>, Comparable<QuizzAnswer> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Pattern(regexp = ".{1,255}", message = "pattern")
    private String answerLabel;

    public String getAnswerLabel() {
        return answerLabel;
    }

    @Override
    public Long getId() {
        return id;
    }

    public void setAnswerLabel(String param) {
        this.answerLabel = param;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }
}

So I did something like this in JPA:

@Query(value = "select quest from Document doc"
        + " right join doc.questions quest"
        + " join quest.answers"
        + " where doc.id = :documentId"
)
List<QuizzQuestion> findQuestionsByDocumentId(@Param(value = "documentId") final Long documentId);

But several questions aris. I ask on the basic DOCUMENT table but I return a list of "QuizzQuestion" items. So do I have to perform this query in the "DocumentRepository" or "QuizzQuestionRepository" repository.

I've tried both, but in any case, the following errors are returned to me:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quizzQuestionRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.afklm.sopra.repository.QuizzQuestionRepository.findQuestionsByDocumentId(java.lang.Long)!
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:187)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1213)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1053)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1018)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
    ... 52 more
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.afklm.sopra.repository.QuizzQuestionRepository.findQuestionsByDocumentId(java.lang.Long)!
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:92)
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:62)
    at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:72)
    at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:53)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:141)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:209)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:74)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:416)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:206)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:251)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:237)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 63 more
Caused by: 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=quest,role=com.afklm.sopra.entity.Document.questions,tableName=QUIZZ_QUESTION,tableAlias=quizzquest2_,origin=DOCUMENT document0_,columns={document0_.ID ,className=com.afklm.sopra.entity.QuizzQuestion}}] [select quest from com.afklm.sopra.entity.Document doc right join fetch doc.questions quest join fetch quest.answers where doc.id = :documentId]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:331)
    at sun.reflect.GeneratedMethodAccessor60.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:344)
    at com.sun.proxy.$Proxy122.createQuery(Unknown Source)
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:86)
    ... 76 more
Caused by: 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=quest,role=com.afklm.sopra.entity.Document.questions,tableName=QUIZZ_QUESTION,tableAlias=quizzquest2_,origin=DOCUMENT document0_,columns={document0_.ID ,className=com.afklm.sopra.entity.QuizzQuestion}}] [select quest from com.afklm.sopra.entity.Document doc right join fetch doc.questions quest join fetch quest.answers where doc.id = :documentId]
    at org.hibernate.QueryException.generateQueryException(QueryException.java:137)
    at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:120)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:234)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:126)
    at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:88)
    at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:190)
    at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
    at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
    at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1800)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:328)
    ... 82 more
Caused by: 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=quest,role=com.afklm.sopra.entity.Document.questions,tableName=QUIZZ_QUESTION,tableAlias=quizzquest2_,origin=DOCUMENT document0_,columns={document0_.ID ,className=com.afklm.sopra.entity.QuizzQuestion}}]
    at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:227)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:923)
    at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:691)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:663)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299)
    at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:278)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
    ... 90 more

It's probably something easy to solve, but I'm a little lost. If anyone can enlighten me, thanks in advance to him! :D

Simon Martinelli :

For the query problem there are missing spaces:

As a good practice put them in the beginning of multiline string so you can see it.

Then you want to return QuizzQuestion so return these and not the Document:

@Query(value = "select quest from QuizzQuestion quest"
        + " join fetch quest.answers"
        + " where quest.document.id = :documentId"
)
List<QuizzQuestion> findQuestionsByDocumentId(@Param(value = "documentId") final Long documentId);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=8136&siteId=1