Кажется, что вывод типа не работает vavr Try работает с функцией fetchOne() в jOOQ

Я использую vavr и jOOQ, две фантастические библиотеки, появившиеся в последнее время, что позволяет нам использовать функциональные диалекты в обычных приложениях на Java-сервере.

Я пытаюсь использовать jOOQ, что эквивалентно количеству выбора SQL (*).

Запрос формируется так:

 ResultQuery query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

Генератор jOOQ работал отлично, и здесь нет никакого несоответствия типов. Итак, я думаю, запрос правильно сформирован.

Затем я использую Try vavr, таким образом:

Optional<Integer> mayBeCount = Optional.empty();

try (final Connection cn = this.ds.getConnection()) {

    DSLContext dsl = DSL.using(cn, this.dialect);

    Try<Integer> countFromDBAttempted =
               Try
               .of(() -> prepareCountOfGamesPlayedQuery(dsl,criteriaAllFieldsTeam))
               .map(e -> e.fetchOne(0, Integer.class)) // Here's the problem!
               .onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));

           mayBeCount = (countFromDBAttempted.isFailure() ? Optional.empty() : Optional.of(countFromDBAttempted.getOrElse(0)));

  } catch (SQLException ex) {

    logger.warning(
         String.format("DB(jOOQ): Failed, counting games played, using criteria {%s},reason={%s}",criteriaAllFieldsTeam.toString(),ex.getMessage()));
  }

  return (mayBeCount);

Компилятору не удается определить тип поля, несмотря на помощь, которую я ему оказываю, описывая целевой тип: Integer.class!

../ReportByTeamRecordProducerImpl.java:66: error: incompatible types: Try<Object> cannot be converted to Try<Integer>
.onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));
                         ^

Неудивительно, что когда я приводил тип к коду, код работал совершенно нормально. Я просто представляю явное приведение в строке, которую компилятор считает.. эээ... неприятным!

Try<Integer> countFromDBAttempted =
   Try
   // The following function returns the ResultQuery shown above
   .of(() -> prepareCountOfGamesPlayedQuery(dsl,criteriaAllFieldsTeam))
   // Casting below, because of some incompatibility between vavr and jOOQ
  .map(e -> ((Integer) e.fetchOne(0, Integer.class)))
  .onFailure(e -> logger.warning(String.format("Count Of Games Played, status=Failed, reason={%s}",e.getMessage())));

Я попробовал несколько других способов, основанных на моем понимании библиотеки jOOQ и особенно этого объяснения @ Lukas Eder.

То, что я до сих пор не пробовал, это ввести конвертер, потому что для одного значения поля, которое кажется ненужным, на мой взгляд! Однако, если это так, то я хотел бы получить подсказку.

В ответ на @ Lukas Eder:

private ResultQuery prepareCountOfGamesPlayedQuery(DSLContext dsl, CriteriaAllFieldsTeam criteriaAllFieldsTeam) {

        Instant fromWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getFromWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        Instant toWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getToWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        ResultQuery query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

        return (query);
    }

После этого, Лукас, я изменил метод следующим образом:

private ResultQuery<Record1<Integer>> prepareCountOfGamesPlayedQuery(DSLContext dsl, CriteriaAllFieldsTeam criteriaAllFieldsTeam) {

        Instant fromWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getFromWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        Instant toWhenInUTCInstant =
                convertToDBCompatibleInstantUTC(
                        criteriaAllFieldsTeam.getDate_range().getToWhen(),
                        criteriaAllFieldsTeam.getDate_range().getInTimeZone());

        ResultQuery<Record1<Integer>> query = dsl.selectCount()
                .from(Tables.SH_PLAYER_REPORT)
                .join(Tables.SH_PLAYERS)
                .on(Tables.SH_PLAYERS.PLAYER_ID.eq(Tables.SH_PLAYER_REPORT.PLAYER_ID))
                .join(Tables.SH_LOCATION)
                .on(Tables.SH_LOCATION.LOCATION_ID.eq(Tables.SH_PLAYERS.LOCATION))
                .and(Tables.SH_PLAYER_REPORT.START_ON.ge(Timestamp.from(fromWhenInUTCInstant)))
                .and(Tables.SH_PLAYER_REPORT.START_ON.le(Timestamp.from(toWhenInUTCInstant)))
                .and(Tables.SH_LOCATION.LOCATION_ID.eq(criteriaAllFieldsTeam.getLocation_id()));

        return (query);
    }

.. и теперь мир снова преобладает в мире!

Спасибо, Лукас!

1 ответ

Решение

Учитывая код, который вы предоставили до сих пор, и предполагая, что опечаток нет, это, вероятно, вызвано вашей необработанной ссылкой на тип ResultQuery, использование ResultQuery<?> или же ResultQuery<Record1<Integer>> вместо.

Никогда не используйте сырые типы, если вам не нужно. И вы, вероятно, нет.

Другие вопросы по тегам