Why do I get an invalid path when I try and construct a JPQL join query?

那年仲夏 提交于 2019-12-19 10:52:32

问题


I’m using JPA 2.1, Hibernate 4.3.6.Final, and MySQL 5.5.37. How do I write a JPQL query that does a join? I’m trying below

    final String jpqlQuery = "SELECT m FROM Message m LEFT JOIN MessageReadDate mr " + 
            " INNER JOIN m.group g " + 
            " LEFT JOIN g.classroom c " + 
            " LEFT JOIN c.ROSTER u WHERE " + 
            " u.USER = :recipient AND " + 
            " u.ENABLED = 1 AND " + 
            " c.ENABLED = 1 AND " + 
            " g.NAME = '' AND " +
            " m.author <> :author";
    Query query = m_entityManager.createQuery(jpqlQuery);

but getting the error “Path expected for join! … Invalid path: 'g.classroom'”.

org.hibernate.hql.internal.ast.ErrorCounter -  Path expected for join!
 Path expected for join!
        at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:379)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3903)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3689)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3567)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:708)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:564)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:249)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:278)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
        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:167)
        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)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
        at com.sun.proxy.$Proxy68.createQuery(Unknown Source)
        at org.mainco.subco.messaging.repo.MessageDaoImpl.getUnreadClassAnnouncements(MessageDaoImpl.java:161)
        at org.mainco.subco.messaging.repo.MessageDaoImpl.getUnreadMessages(MessageDaoImpl.java:140)
        at org.mainco.subco.messaging.repo.MessageDaoIT.testGetUnreadMessages(MessageDaoIT.java:125)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:  74)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    [ERROR]: org.hibernate.hql.internal.ast.ErrorCounter -  Invalid path: 'g.classroom'
    [ERROR]: org.hibernate.hql.internal.ast.ErrorCounter -  Invalid path: 'g.classroom'
     Invalid path: 'g.classroom'
        at org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:129)
        at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:225)
        at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:126)
        at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:387)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3903)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3689)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3567)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:708)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:564)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
        at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:249)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:278)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
    …

My message entity is as follows …

@Entity
@Table(name = "msg")
public class Message
{

    @Id
    @NotNull
    @GeneratedValue(generator = "uuid-strategy")
    @Column(name = "ID")
    private String id;

    @Column(name = "MESSAGE", columnDefinition="LONGTEXT")
    private String message;

    @ManyToOne
    @JoinColumn(name = "GROUP_ID", nullable = false, updatable = true)
    private Group group;

And my group entity is as follows …

@Entity
@Table(name = "msg_group")
public class Group
{
    @Id
    @NotNull
    @GeneratedValue(generator = "uuid-strategy")
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME")
    private String name;

    @ManyToOne
    @JoinColumn(name = "CLASSROOM_ID", nullable = true, updatable = true)
    private Classroom classroom;

So why can’t I reference the “classroom” attribute?

Thanks, - Dave


回答1:


The issue reported by Hibernate is in the first row:

final String jpqlQuery = "SELECT m FROM Message m LEFT JOIN MessageReadDate mr "...

in the LEFT JOIN statement. In hql, the JOIN must be expressing the relation, e.g.

LEFT JOIN m.MessageReadDate mr // the m is referencing the MessageReadDate

If there is no reference, we can still use that, but with Cartesian product

FROM Message m, MessageReadDate mr

in that case, the CROSS JOIN will be issued

See the:

  • 16.2. The from clause

small cite:

Multiple classes can appear, resulting in a cartesian product or "cross" join.

from Formula, Parameter
from Formula as form, Parameter as param
  • 16.3. Associations and joins

You can also assign aliases to associated entities or to elements of a collection of values using a join. For example:

from Cat as cat
    inner join cat.mate as mate



回答2:


If you want to use JOIN's in HQL then you have to use it only on the properties of the class which is mentioned in From clause.

What it means is, in this particular line:

SELECT m FROM Message m LEFT JOIN MessageReadDate mr 

hibernate checks if MessageReadDate is defined as a property in Message class which is considered as path here. As there is nothing called MessageReadDate it throws an exception.

So to fix this issue, add the required property for MessageReadDate class in Message class, lets say mrd (you can have your relation as one-to-one or on-to-many or etc) and then use the query like this:

SELECT m FROM Message m LEFT JOIN m.mrd

in this way we are telling hibernate how to join the message with its corresponding properties so the path for join is clear to hibernate.



来源:https://stackoverflow.com/questions/26063475/why-do-i-get-an-invalid-path-when-i-try-and-construct-a-jpql-join-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!