`Type cannot be null` exception when trying to run out Stored Procedure using Spring Data JPA

风格不统一 提交于 2021-02-05 09:40:52

问题


I am trying to invoke a Stored Procedure whose signature looks like the following:

CREATE OR REPLACE PROCEDURE FIND_FIRST_BOOKMARK_GT(bookmark IN NUMBER, cur OUT SYS_REFCURSOR)

I am using Spring-Data JPA and have tried a number of different variants, but all of them follow more or less the following pattern. My entity model is decorated as follows:

@NamedStoredProcedureQuery(name = "Response.findFirstBookmarkGreaterThan", procedureName = "FIND_FIRST_BOOKMARK_GT",
    resultClasses = Response.class,
    parameters = {
        @StoredProcedureParameter(name = "bookmark", mode = ParameterMode.IN, type = Long.class),
        @StoredProcedureParameter(name = "cur", mode = ParameterMode.REF_CURSOR, type = void.class)
    })
})

Then I have my repository which looks like the following:

@Repository
public interface ResponseRepository extends CrudRepository<Response, Long>{
    @Procedure("Response.findFirstBookmarkGreaterThan")
    Response findFirstBookmarkGreaterThan(@Param("bookmark") Long bookmark);
}

I have followed the instructions from quite a few examples, but I am always left with the same error, namely:

java.lang.IllegalArgumentException: Type cannot be null
at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.setHibernateType(AbstractParameterRegistrationImpl.java:182) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:131) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:140) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.procedure.internal.AbstractParameterRegistrationImpl.<init>(AbstractParameterRegistrationImpl.java:97) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.procedure.internal.NamedParameterRegistration.<init>(NamedParameterRegistration.java:41) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.registerParameter(ProcedureCallImpl.java:344) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.jpa.internal.StoredProcedureQueryImpl.registerStoredProcedureParameter(StoredProcedureQueryImpl.java:152) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.newAdhocStoredProcedureQuery(StoredProcedureJpaQuery.java:175) ~[spring-data-jpa-1.9.4.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.createStoredProcedure(StoredProcedureJpaQuery.java:130) ~[spring-data-jpa-1.9.4.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.doCreateQuery(StoredProcedureJpaQuery.java:89) ~[spring-data-jpa-1.9.4.RELEASE.jar:na]
at org.springframework.data.jpa.repository.query.StoredProcedureJpaQuery.createQuery(StoredProcedureJpaQuery.java:80) ~[spring-data-jpa-1.9.4.RELEASE.jar:na]
......

Any ideas what is wrong here?


回答1:


Using native Query we can also call store procedure. If you are using MySQL then following will be the systex:

 @Query(nativeQuery = true,value = "call getEmployeeList")
 List<Employee> getEmployeeList();



回答2:


I was not able to get this syntax working as such, however, the notion of retrieving from a stored procedure is effectively a shorthand for selecting from (possibly a view) mixed with applying some input based function. To that effect, I have replaced my stored procedure with a function / table that yields the same effect.

@Query("SELECT r FROM RESPONSES r WHERE BOOKMARK = FIND_FIRST_BOOKMARK_GT(:bookmark)")
Response findFirstBookmarkGreaterThan(@Param("bookmark") Long bookmark);

This uses the @Query syntax in conjunction with a table and a function, whose overall logic is identical to calling the stored procedure I had intended. Although a little more difficult to follow perhaps, the syntax is at least much shorter than using the @NamedStoredProcedureQuery.

The function does the same thing the stored procedure originally did EXCEPT for the last part which was a SELECT INTO, this is now encapsulated as part of the @Query.




回答3:


Faced with the same issue using @Procedure. As a workaround, you could refer to the entityManager in the service class and call procedure from it.

@Service
public interface ResponseService {

    @PersistenceContext
    EntityManager entityManager;

    public Response findFirstBookmarkGreaterThan(Long bookmark){
          Query query  = entityManager.createNamedStoredProcedureQuery("Response.findFirstBookmarkGreaterThan");
          query.setParameter("bookmark", bookmark);
          return query.getFirstResult();
    };
}

Note that Response must be an @Entity.




回答4:


This is an old question, but I faced with same issue and get fixed finally after a couple of hours of "read docs-try-error". Maybe this could be useful to someone. Your repository must look like this:

@Repository
public interface ResponseRepository extends CrudRepository<Response, Long>{
    @Procedure(name = "Response.findFirstBookmarkGreaterThan")
    Response findFirstBookmarkGreaterThan(@Param("bookmark") Long bookmark);
}

The key is at @Procedure annotation. Use "name" instead of "value" (by default) when coding this annotation. This article at Baeldung blog gave me the final pull to resolve this error: https://www.baeldung.com/spring-data-jpa-stored-procedures.



来源:https://stackoverflow.com/questions/38021968/type-cannot-be-null-exception-when-trying-to-run-out-stored-procedure-using-sp

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