Java @带有Spring数据JPA存储库的NamedStoredProcedureQuery-类型不能为null错误

Java @带有Spring数据JPA存储库的NamedStoredProcedureQuery-类型不能为null错误,java,spring,hibernate,jpa,Java,Spring,Hibernate,Jpa,我有一个JPA实体类RequestSummary,它最初是从数据库视图填充的。出于性能方面的原因,我试图重构它以使用存储过程,但在正确设置它时遇到了问题 我有一个存储过程“sp\u bsc\u request\u summary”,它将一个staffId作为参数 我的spring数据存储库如下所示 public interface RequestSummaryRepository extends JpaRepository<RequestSummary, Long> { @Proc

我有一个JPA实体类RequestSummary,它最初是从数据库视图填充的。出于性能方面的原因,我试图重构它以使用存储过程,但在正确设置它时遇到了问题

我有一个存储过程“sp\u bsc\u request\u summary”,它将一个staffId作为参数

我的spring数据存储库如下所示

public interface RequestSummaryRepository extends JpaRepository<RequestSummary, Long> {

@Procedure("procedureFindAll")
public List<RequestSummary> procedureFindAll(@Param("staffId") Long staffId);
}
@NamedStoredProcedureQuery(name = "procedureFindAll", procedureName = "sp_bsc_request_summary", parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class, name = "staffId")}, resultSetMappings = "mapping")

@SqlResultSetMapping(name = "mapping", classes = {@ConstructorResult(targetClass = RequestSummary.class, columns = {
@ColumnResult(name = "bsc_request_id", type = Long.class), @ColumnResult(name = "created_date", type = Date.class),
@ColumnResult(name = "transaction_size", type = BigDecimal.class),
@ColumnResult(name = "approval_status_id", type = Long.class),
@ColumnResult(name = "approval_status_desc", type = String.class), @ColumnResult(name = "approval_key", type = String.class),
@ColumnResult(name = "captain_staff_id", type = Long.class), @ColumnResult(name = "captain_name", type = String.class),
@ColumnResult(name = "captain_country_id", type = Long.class), @ColumnResult(name = "captain_country", type = String.class),
@ColumnResult(name = "est_fee_usd", type = BigDecimal.class), @ColumnResult(name = "client_vision_id", type = String.class),
@ColumnResult(name = "client_full_name", type = String.class), @ColumnResult(name = "client_country_id", type = Long.class),
@ColumnResult(name = "country_description", type = String.class), @ColumnResult(name = "mastergroup", type = String.class),
@ColumnResult(name = "decision_staff_id", type = Long.class), @ColumnResult(name = "decision_staff_name", type = String.class),
@ColumnResult(name = "temporary_client_name", type = String.class)

})})
@Entity
public class RequestSummary {

@Id
private Long id;
...
@Autowired
private EntityManager entityManager;

public List<RequestSummary> findAll(Long staffId) {
   StoredProcedureQuery storedProcedureQuery = entityManager.createNamedStoredProcedureQuery("sp_bsc_request_summary");
   storedProcedureQuery.setParameter("staffId", staffId);
   storedProcedureQuery.execute();
   return storedProcedureQuery.getResultList();
}
所以有几件事我不确定

  • 该实体不再由“vw_bsc_请求_摘要”支持,因此我是否要完全删除@Table注释?如果我这样做了,JPA会抱怨找不到默认名称为RequestSummary的表
  • 如果这个实体没有表或视图的支持,我应该包括@Entity注释吗
使用上面的代码,当我尝试运行集成测试来调用该方法时

@Test
public void testFindAll() {
    final List<RequestSummary> requests = this.summaryRepo.procedureFindAll(61953104L);
    Assert.assertNotNull(requests);
    Assert.assertTrue(requests.size() > 0);
}
当我调用该方法时,尽管我得到如下堆栈跟踪

2016-12-16 10:58:10,565 ERROR [http-bio-8080-exec-28] controller.RequestController - Current CallableStatement ou was not a ResultSet, but getResultList was called
java.lang.IllegalStateException: Current CallableStatement ou was not a ResultSet, but getResultList was called
at org.hibernate.jpa.internal.StoredProcedureQueryImpl.getResultList(StoredProcedureQueryImpl.java:336)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:362)
at com.sun.proxy.$Proxy82.getResultList(Unknown Source)
at com.company.gbgcf.bsc.service.RequestService.findAll(RequestService.java:112)
at com.company.gbgcf.bsc.service.RequestService.findAll(RequestService.java:125)
at com.company.gbgcf.bsc.controller.RequestController.findAllRequests(RequestController.java:102)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:747)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:676)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:369)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at com.company.gbgcf.bsc.filters.AuthenticatedSessionFilter.doFilter(AuthenticatedSessionFilter.java:143)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:168)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
起初我认为这可能是因为该过程正在打印一些调试信息以及记录集,但是在删除这些打印语句之后,我仍然会得到相同的错误

更新2

添加多一点日志将确认调用了正确的过程,并且参数已绑定

    2016-12-16 11:54:53,883 DEBUG [http-bio-8080-exec-25] spi.SqlStatementLogger - 
    {call sp_bsc_request_summary(?)}
    Hibernate: 
    {call sp_bsc_request_summary(?)}
    2016-12-16 11:54:53,904 TRACE [http-bio-8080-exec-25] sql.BasicBinder - binding parameter [1] as [BIGINT] - [61953104]
2016-12-16 11:54:53,984 DEBUG [http-bio-8080-exec-1] annotation.AbstractMessageConverterMethodProcessor - Written [{"forename":"CRAIG","surname":"GORDON","roleNames":["DP_DEFAULT_VIEW_LAF","DP_MENU_DELETE","GB_ADVISORY_DEAL_STATUS_UPDATE_REPORT_USER","DP_ADD_NEW_DEAL","DP_CF_Report","GB_CAPITAL_FINANCING_REPORT","LAF_MD_PIPELINE_REPORT_USER","LAF_CANNED_REPORT","DCM_DEAL_PIPELINE_USER","DP_DEAL_PIPELINE_USER","GB_ADVISORY_NEW_DEALS_REPORT_USER","LAF_DEAL_CLOSE_REPORT","DP_SHOW_CLIENT_ON_REPORTS","DCM_CAPITAL_FINANCING_REPORT","LAF_DEAL_PIPELINE_USER","GB_CANNED_REPORT","DP_EXT_Deal_Access_DCM","GB_DEAL_PIPELINE_USER","Clone_GB_Deal","DP_EXT_Deal_Access_MnA"]}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter@d3d0bbc]
2016-12-16 11:54:53,986 DEBUG [http-bio-8080-exec-1] servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'bsc': assuming HandlerAdapter completed request handling
2016-12-16 11:54:53,986 DEBUG [http-bio-8080-exec-1] servlet.FrameworkServlet - Successfully completed request
2016-12-16 11:54:53,988 DEBUG [http-bio-8080-exec-1] access.ExceptionTranslationFilter - Chain processed normally
2016-12-16 11:54:53,988 DEBUG [http-bio-8080-exec-1] context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Building Return [isResultSet=false, updateCount=0, extendedReturn=false
2016-12-16 11:54:54,597 DEBUG [http-bio-8080-exec-25] jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
2016-12-16 11:54:54,617 ERROR [http-bio-8080-exec-25] controller.RequestController - Current CallableStatement ou was not a ResultSet, but getResultList was called
java.lang.IllegalStateException: Current CallableStatement ou was not a ResultSet, but getResultList was called
    at org.hibernate.jpa.internal.StoredProcedureQueryImpl.getResultList(StoredProcedureQueryImpl.java:336)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
更新3

终于让它工作了。因此,对于其他遇到问题的人。。。。 错误-
当前CallableStatement ou不是结果集
已通过在我的存储过程中包括
设置nocount on
来解决(这在sybase 15中) 这给我留下了另一个错误,@ConstructorResult无法找到正确的构造函数。这是因为从过程返回的字段推断出的某些数据类型与构造函数预期的数据类型不一致。确定罪魁祸首涉及下载hibernate源jar并在其上设置断点

ConstructorResultColumnProcessor.resolveConstructor(Class targetClass, List<Type> types)
ConstructorResultColumnProcessor.resolveConstructor(类targetClass,列表类型)

一旦这些类型被对齐,它就会像预期的那样工作。

我们几个月前遇到了这个问题,不幸的是,找不到解决方案。我们所做的,您可能也可以,就是创建一个服务,注入实体管理器,然后从那里调用它。这不是最优的,但和您一样,我们也在努力获得纯spring数据jpa解决方案。如果你想沿着这条路走下去,这里有一个解决方案应该适合你

将实体定义稍微更改为

@NamedStoredProcedureQuery(name = "procedureFindAll", 
   procedureName = "sp_bsc_request_summary", 
   parameters = {
     @StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class, name = "staffId")},
   ,resultSetMappings = "mapping"))
@SqlResultSetMapping(name = "mapping", classes = {
   @ConstructorResult(targetClass = RequestSummary.class, columns = {               
      @ColumnResult(name = "bsc_request_id", type = Long.class)
   })
})
在上面,为每个要映射的字段添加ColumnResult。您的服务将是这样的

public interface RequestSummaryRepository extends JpaRepository<RequestSummary, Long> {

@Procedure("procedureFindAll")
public List<RequestSummary> procedureFindAll(@Param("staffId") Long staffId);
}
@NamedStoredProcedureQuery(name = "procedureFindAll", procedureName = "sp_bsc_request_summary", parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class, name = "staffId")}, resultSetMappings = "mapping")

@SqlResultSetMapping(name = "mapping", classes = {@ConstructorResult(targetClass = RequestSummary.class, columns = {
@ColumnResult(name = "bsc_request_id", type = Long.class), @ColumnResult(name = "created_date", type = Date.class),
@ColumnResult(name = "transaction_size", type = BigDecimal.class),
@ColumnResult(name = "approval_status_id", type = Long.class),
@ColumnResult(name = "approval_status_desc", type = String.class), @ColumnResult(name = "approval_key", type = String.class),
@ColumnResult(name = "captain_staff_id", type = Long.class), @ColumnResult(name = "captain_name", type = String.class),
@ColumnResult(name = "captain_country_id", type = Long.class), @ColumnResult(name = "captain_country", type = String.class),
@ColumnResult(name = "est_fee_usd", type = BigDecimal.class), @ColumnResult(name = "client_vision_id", type = String.class),
@ColumnResult(name = "client_full_name", type = String.class), @ColumnResult(name = "client_country_id", type = Long.class),
@ColumnResult(name = "country_description", type = String.class), @ColumnResult(name = "mastergroup", type = String.class),
@ColumnResult(name = "decision_staff_id", type = Long.class), @ColumnResult(name = "decision_staff_name", type = String.class),
@ColumnResult(name = "temporary_client_name", type = String.class)

})})
@Entity
public class RequestSummary {

@Id
private Long id;
...
@Autowired
private EntityManager entityManager;

public List<RequestSummary> findAll(Long staffId) {
   StoredProcedureQuery storedProcedureQuery = entityManager.createNamedStoredProcedureQuery("sp_bsc_request_summary");
   storedProcedureQuery.setParameter("staffId", staffId);
   storedProcedureQuery.execute();
   return storedProcedureQuery.getResultList();
}
。。。
@自动连线
私人实体管理者实体管理者;
公共列表findAll(长staffId){
StoredProcedureQuery StoredProcedureQuery=entityManager.createNamedStoredProcedureQuery(“sp_bsc_请求_摘要”);
storedProcedureQuery.setParameter(“staffId”,staffId);
storedProcedureQuery.execute();
返回storedProcedureQuery.getResultList();
}
我的解决方案是:改变

public List<RequestSummary> findAll(final Long staffId) {...

我以前遇到过这个问题。首先,
@过程
不起作用。所以我选择了
@namedStoredProcedureRequesty
。这是可行的,但我只是发现它有很多管道或锅炉板代码。我优雅/简洁的解决方案是使用
nativeQuery
。试图模仿上面的代码,我的解决方案如下所示:

public List<RequestSummary> findAll(final Long staffId) {
    final StoredProcedureQuery storedProcedureQuery = this.entityManager.createNamedStoredProcedureQuery("procedureFindAll");
    storedProcedureQuery.setParameter("staffId", staffId);
    storedProcedureQuery.execute();
    return storedProcedureQuery.getResultList();
}
public interface ProcedureFindAll extends JpaRepository<RequestSummary, Long> {

    @Query(value = "EXECUTE sp_bsc_request_summary :staffId", nativeQuery = true)
    List<RequestSummary> findAllRequestSummary( @Param( "staffId" ) Long staffId);
}

你能找到一个使用“@procedure”而不是使用entityManager的解决方案吗?我在
@procedure
上做了很多努力,但没有成功。这对我来说很有效,而“普通的旧”程序却没有!似乎与我返回一个复杂对象的事实有关。截至2019年6月,这个问题仍然存在。这是一个很好的解决方案@程序不起作用。谢谢,谢谢!这是一个很好的解决方案,也是我一直在追求的。
@Entity
public class RequestSummary {

    @Id
    private Long id;
    //...code remove for brevity
}