通过JPA实体图形动态获取会引发SQLGrammarException

时间:2017-02-24 16:11:47

标签: spring hibernate spring-mvc jpa

我使用Spring Security和Hibernate实现了基本的用户管理。

以下是包含关系的实体(UserEntityRoleEntityPermissionEntityUserRoleEntityUserPermissionEntity):

UserEntity:

@Entity
@Table(name = "tb_user")
@NamedQuery(name = "User.findById", query = "SELECT u FROM UserEntity u WHERE u.idUser = :userId")
@NamedEntityGraph(
    name = "graph.userRoles.role", 
    attributeNodes = {
        @NamedAttributeNode(value = "userRoles", subgraph = "userRolesGraph"),
        @NamedAttributeNode(value = "userPermissions", subgraph = "userPermissionsGraph")
    }, 
    subgraphs = {
        @NamedSubgraph(name = "userRolesGraph", attributeNodes = @NamedAttributeNode("role")),
        @NamedSubgraph(name = "userPermissionsGraph", attributeNodes = @NamedAttributeNode("permission"))
    }
)
public class UserEntity implements Serializable
{
   [...]

   @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
   private Set<UserRoleEntity> userRoles;
   @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
   private Set<UserPermissionEntity> userPermissions;

   [...]
}

UserRoleEntity:

@Entity
public class UserRoleEntity implements Serializable
{
    [...]

    @JoinColumn(name = "id_role", referencedColumnName = "id_role")
    @ManyToOne(fetch = FetchType.LAZY)
    private RoleEntity role;
    @JoinColumn(name = "id_user", referencedColumnName = "id_user")
    @ManyToOne(fetch = FetchType.LAZY)
    private UserEntity user;

    [...]
}

UserPermissionEntity:

@Entity
public class UserPermissionEntity implements Serializable
{
    [...]

    @JoinColumn(name = "id_user", referencedColumnName = "id_user")
    @ManyToOne(fetch = FetchType.LAZY)
    private UserEntity user;
    @JoinColumn(name = "id_permission", referencedColumnName = "id_permission")
    @ManyToOne(fetch = FetchType.LAZY)
    private PermissionEntity permission;

    [...]
}

我只想获得一个特定的UserEntity及其ID和fetch:

  • UserEntity.userRoles.role
  • UserEntity.userPermissions.permission

这是Dao方法:

@Override
@Transactional(readOnly = true)
public UserEntity getUserByIdGraph(Integer userId)
{
    TypedQuery<UserEntity> query = this.entityManager.createNamedQuery("User.findById", UserEntity.class);

    query.setParameter("userId", userId);
    query.setHint("javax.persistence.fetchgraph",
            this.entityManager.getEntityGraph("graph.userRoles.role"));
     UserEntity userEntity = query.getSingleResult(); //Fails here

    return (userEntity);
}

问题是我有以下错误:

Etat HTTP 500 - Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'left outer join tb_permission_user userpermis3_ on userentity0_.id_user=userperm' at line 1
    sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    com.mysql.jdbc.Util.getInstance(Util.java:381)
    com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1030)
    com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
    com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
    com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
    com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
    com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
    com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
    com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1885)
    org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:80)
    org.hibernate.loader.Loader.getResultSet(Loader.java:2065)
    org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
    org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1838)
    org.hibernate.loader.Loader.doQuery(Loader.java:909)
    org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
    org.hibernate.loader.Loader.doList(Loader.java:2553)
    org.hibernate.loader.Loader.doList(Loader.java:2539)
    org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2369)
    org.hibernate.loader.Loader.list(Loader.java:2364)
    org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
    org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
    org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:231)
    org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)
    org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
    org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:573)
    org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:495)
    org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getSingleResult(CriteriaQueryTypeQueryAdapter.java:71)
    com.az.metal.dao.impl.UserDaoImpl.getUserByIdGraph(UserDaoImpl.java:110)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:483)
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    com.sun.proxy.$Proxy576.getUserByIdGraph(Unknown Source)
    com.az.metal.service.impl.UserServiceImpl.getUserByIdGraph(UserServiceImpl.java:212)
    com.az.metal.controller.UserController.view(UserController.java:77)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:483)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.bufferAndPostProcess(ContentBufferingFilter.java:169)
    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.doFilter(ContentBufferingFilter.java:126)
    org.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:120)
    org.sitemesh.config.ConfigurableSiteMeshFilter.doFilter(ConfigurableSiteMeshFilter.java:163)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)

我不明白发生了什么,因为如果我分别只提取userRoles.roleuserPermissions.permission,那就有效了。但是这两个子图一起失败(使用javax.persistence.loadgraph时也是如此)!

我真的迷路了。

PS:我尝试使用注释@EntityGraph使用attributePaths,但NetBeans无法识别它!你知道正确的Maven包使用@EntityGraph注释吗?

非常感谢你的帮助!

1 个答案:

答案 0 :(得分:0)

我知道这不会直接解决您的问题,但我觉得我应该将其作为应用程序设计说明。您似乎使用实体来描述用户&lt; - &gt;角色(UserRoleEntity)和用户&lt; - &gt;权限(UserPermissionEntity)之间的实体关系。您是否考虑过使用@JoinTables来简化这些映射?

示例:

@Entity
public class UserEntity implements Serializable {
    @OneToMany
    @JoinTable(name="USER_ROLE",
        joinColumns= @JoinColumn(name="USER_ID"),
        inverseJoinColumns= @JoinColumn(name="ROLE_ID"))
    private Set<RoleEntity> userRoles;

    @OneToMany
    @JoinTable(name="USER_PERM",
        joinColumns= @JoinColumn(name="USER_ID"),
        inverseJoinColumns= @JoinColumn(name="PERM_ID"))
    private Set<PermissionEntity> userPermissions;
}

@Entity
public class RoleEntity {
    @ManyToOne
    @JoinTable(name = "USER_ROLE", 
        joinColumns = @JoinColumn(name = "ROLE_ID"), 
        inverseJoinColumns = @JoinColumn(name = "USER_ID"))
    private UserEntity user;
}

@Entity
public class PermissionEntity {
    @ManyToOne
    @JoinTable(name = "USER_PERM", 
        joinColumns = @JoinColumn(name = "PERM_ID"), 
        inverseJoinColumns = @JoinColumn(name = "USER_ID"))
    private UserEntity user;
}