Сохранить значение хранимой процедуры с помощью JPA - PullRequest
0 голосов
/ 09 мая 2018

Я пытаюсь использовать JPA (и Spring Boot 2) для выполнения хранимой процедуры SQL Server.Вот процедура:

CREATE Procedure [dbo].[GetStatus] 
@statusId   char(32),
@bar    int
AS
BEGIN TRY
    SELECT IIF(COUNT(1)>0 , 1, 0)   FROM Status WITH (NOLOCK) 
    WHERE statusId = @statusId AND bar = @bar
END TRY
BEGIN CATCH
    EXEC EventLog @@PROCID
END CATCH
GO

Я пытаюсь получить возвращаемое значение, но не могу найти способ сделать это.Моя сущность:

@Entity
@Table(name = "status")
@NamedStoredProcedureQueries({
        @NamedStoredProcedureQuery(name = "getStatusByStatusId",
                procedureName = "GetStatus",
                parameters = {
                        @StoredProcedureParameter(mode = ParameterMode.IN, name = "statusId", type = String.class),
                        @StoredProcedureParameter(mode = ParameterMode.IN, name = "bar", type = Integer.class)                    })
})
public class Status implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private Integer bar;
    private String statusId;
    private Date createDate;
}

А мой репозиторий:

@Repository
public interface StatusRepository extends JpaRepository<Status, Long> {
    @Procedure("GetStatus")
    int getStatusByStatusId(@Param("statusId") String statusId, @Param("bar") Integer bar);
}

Когда я запускаю этот метод из уровня обслуживания, я получаю ошибку:

«Параметр out не был определен для хранимой процедуры ...»

Я попытался добавить параметр out (назвав его count и введите Integer).Я пробовал List, Object [], но ничего не получалось.Единственное, что сработало, это если я изменил метод репозитория, чтобы вернуть void.Но в этом случае я не могу получить возвращаемое значение.Итак, мой вопрос, как я могу получить это значение SELECT?Любая помощь приветствуется.Мой app.yml имеет:

  datasource:
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://dev.lsd.com:1433;databaseName=Qrex;integratedSecurity=true;MultiSubnetFailover=true;authenticationScheme=JavaKerberos
    username:
    password:
  jpa:
    hibernate:
      ddl-auto: none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    show-sql: true
    database-platform: org.hibernate.dialect.SQLServerDialect
    database: sql_server

, и моя зависимость от gradle:

compile "com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8"

1 Ответ

0 голосов
/ 09 мая 2018

Я не уверен, что JPA может обрабатывать хранимые процедуры, возвращая произвольное количество наборов результатов и / или счетчиков обновлений и / или сообщений об ошибках. Все примеры, которые я видел, довольно просты. Ваша процедура возвращает либо:

  • Набор результатов, содержащий проекцию (не сущность!)
  • Что бы ни возвращала процедура EventLog. Может быть что угодно

Вот как это сделать напрямую с JDBC (нет параметров OUT, поэтому подойдет обычный PreparedStatement.

Вот как можно получить только один набор результатов с помощью JDBC:

try (PreparedStatement stmt = connection.prepareStatement(
    "EXEC [GetStatus] ?, ?"
)) {
    stmt.setString(1, statusId);
    stmt.setInt(2, bar);

    if (stmt.execute()) {
        try (ResultSet rs = stmt.getResultSet()) {
            // Do your thing
        }
    }
}

Вот как можно получить произвольное количество наборов результатов

В случае, если вы хотите получить то, что также производит EventLog, вы можете вместо этого вызвать его:

try (PreparedStatement stmt = connection.prepareStatement(
    "EXEC [GetStatus] ?, ?"
)) {
    stmt.setString(1, statusId);
    stmt.setInt(2, bar);

    fetchLoop:
    for (int i = 0, updateCount = 0; i < 256; i++) {
        boolean result = (i == 0)
            ? s.execute()
            : s.getMoreResults();

        if (result)
            try (ResultSet rs = s.getResultSet()) {
                System.out.println("Result      :");

                while (rs.next())
                    System.out.println("  " + rs.getString(1));
            }
        else if ((updateCount = s.getUpdateCount()) != -1)
            System.out.println("Update Count: " + updateCount);
        else
            break fetchLoop;
    }
}

Я описал этот подход получения произвольных результирующих наборов и количества обновлений более подробно здесь , в частности, также о том, как правильно получать исключения и предупреждения.

Если вы используете этот подход, вы можете включить эту логику в некоторый библиотечный код.

Использование jOOQ

Существует также возможность использовать jOOQ для этих вещей (отказ от ответственности: я работаю на поставщика), в случае чего вы можете позвонить:

Results results = ctx.fetchMany("EXEC [GetStatus] ?, ?", statusId, bar);

Чтобы получить тип org.jooq.Results, который оборачивает чередующиеся наборы результатов, счетчики обновлений, исключения и предупреждения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...