java类型推断似乎失败了vavr在jooq的fetchone()函数上的尝试

anauzrmj  于 2021-06-17  发布在  Mysql
关注(0)|答案(1)|浏览(483)

我正在使用vavr和jooq,这是最近推出的两个非常棒的库,允许我们在常规java服务器应用程序中使用函数方言。
我正在尝试使用jooq,它相当于sql的select count(*)。
查询的形式如下:

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的生成器工作得很好,这里没有任何类型不匹配。所以,我猜,查询的格式是正确的。
然后,我使用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图书馆的理解,特别是@lukaseder的解释,我尝试了其他几种方法。
到目前为止,我还没有尝试引入一个转换器,因为对于单个字段值,在我看来,这似乎是不必要的!不过,如果是这样的话,我想给你一个提示。
针对@lukaseder:

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);
    }

.. 现在世界又恢复了和平!
谢谢,卢卡斯!

kq0g1dla

kq0g1dla1#

考虑到目前为止您提供的代码,并且假设没有输入错误,这可能是由于您对的原始类型引用造成的 ResultQuery . 使用 ResultQuery<?> 或者 ResultQuery<Record1<Integer>> 相反。
永远不要使用原始类型,除非你真的需要。而你可能没有。

相关问题