【问题标题】:A nice way to pass complex result types in JOOQ在 JOOQ 中传递复杂结果类型的好方法
【发布时间】:2022-08-15 14:18:18
【问题描述】:

我一直在使用 JOOQ 3.17 的一些新功能,例如类型安全的嵌套表记录与隐式连接混合,如下所述:

https://blog.jooq.org/projecting-type-safe-nested-tablerecords-with-jooq-3-17/

我们有一个复杂的视图,您可以在其中修改“公司”对象的许多属性。我们的旧代码在一个相当大的 UI 上为公司对象的 CRUD 相关记录提供了不计其数的休眠方法。现在我想在 JOOQ 中重写它。我想出了一个查询,它可以提取 CompanyRecord 和相关记录,如下所示:

Record4<CompanyRecord, Result<ServiceCompanyPreferenceRecord>, Result<SubsidiaryRecord>, Result<CompanyCo2ParameterRecord>> fancyTypeResult =
        dslContext.get().select(
                        Tables.COMPANY,
                        multiset(
                                selectFrom(Tables.SERVICE_COMPANY_PREFERENCE)
                                        .where(Tables.SERVICE_COMPANY_PREFERENCE.COMPANY_ID.eq(Tables.COMPANY.ID))
                        ),
                        multiset(
                                selectFrom(Tables.SUBSIDIARY)
                                        .where(Tables.SUBSIDIARY.COMPANY_ID.eq(Tables.COMPANY.ID))
                        ),
                        multiset(
                                selectFrom(Tables.COMPANY_CO2_PARAMETER)
                                        .where(Tables.COMPANY_CO2_PARAMETER.COMPANY_ID.eq(Tables.COMPANY.ID))
                        )
                )
                .from(Tables.COMPANY)
                .where(Tables.COMPANY.ID.eq(companyId))
                .fetchOne();

这太棒了,因为我可以修改和保存 CompanyRecord 或相关的 ServiceCompanyPreferenceRecord、SubsidiaryRecord 或 CompanyCo2ParameterRecord,并且数据库中的这些行已更新。

我遇到的一个问题是传递类型\"Record4&lt;CompanyRecord, Result&lt;ServiceCompanyPreferenceRecord&gt;, Result&lt;SubsidiaryRecord&gt;, Result&lt;CompanyCo2ParameterRecord&gt;&gt;\" 相当冗长。所以有一个功能可以找到一家公司的所有记录,像这样

public Record4<CompanyRecord, Result<ServiceCompanyPreferenceRecord>, Result<SubsidiaryRecord>, Result<CompanyCo2ParameterRecord>> loadCompanyAndRelatedPreferences(Long companyId){ ....

可能有点尴尬。我想知道如果简单地制作一个包含\"Record4&lt;CompanyRecord, Result&lt;ServiceCompanyPreferenceRecord&gt;, Result&lt;SubsidiaryRecord&gt;, Result&lt;CompanyCo2ParameterRecord&gt;&gt;\" 类型字段的 POJO 是否会更容易,因为我可以使用该 POJO 而无需一遍又一遍地重写该类型。另一个想法是这是 Java 记录的一个很好的用例吗?

我们有许多遵循这种模式的屏幕。拉记录和相关记录,对它们进行 CRUD。关于处理这个问题的好方法有什么想法吗?

  • 看起来我可以调用 fetchInto(SomeRecordClass.class) 但这没有编译时间检查 JOOQ 的结果是否与 Record Class 的构造函数匹配。记录是指JDK16记录。

标签: java sql jooq


【解决方案1】:

您可以使用convertFrommapping。这是来自https://github.com/72services/jtaf4 的示例

return dsl
        .select(
            COMPETITION.NAME,
            COMPETITION.COMPETITION_DATE,
            COMPETITION.ALWAYS_FIRST_THREE_MEDALS,
            COMPETITION.MEDAL_PERCENTAGE,
            multiset(
                select(
                    CATEGORY.ABBREVIATION,
                    CATEGORY.NAME,
                    CATEGORY.YEAR_FROM,
                    CATEGORY.YEAR_TO,
                    multiset(
                        select(
                            CATEGORY_ATHLETE.athlete().FIRST_NAME,
                            CATEGORY_ATHLETE.athlete().LAST_NAME,
                            CATEGORY_ATHLETE.athlete().YEAR_OF_BIRTH,
                            CATEGORY_ATHLETE.athlete().club().NAME,
                            multiset(
                                select(
                                    RESULT.event().ABBREVIATION,
                                    RESULT.RESULT_,
                                    RESULT.POINTS
                                )
                                    .from(RESULT)
                                    .where(RESULT.ATHLETE_ID.eq(CATEGORY_ATHLETE.athlete().ID))
                                    .and(RESULT.COMPETITION_ID.eq(COMPETITION.ID))
                                    .and(RESULT.CATEGORY_ID.eq(CATEGORY.ID))
                                    .orderBy(RESULT.POSITION)
                            ).convertFrom(r -> r.map(mapping(CompetitionRankingData.Category.Athlete.Result::new)))
                        )
                            .from(CATEGORY_ATHLETE)
                            .where(CATEGORY_ATHLETE.CATEGORY_ID.eq(CATEGORY.ID))
                    ).convertFrom(r -> r.map(mapping(CompetitionRankingData.Category.Athlete::new)))
                )
                    .from(CATEGORY)
                    .where(CATEGORY.SERIES_ID.eq(COMPETITION.SERIES_ID))
                    .orderBy(CATEGORY.ABBREVIATION)
            ).convertFrom(r -> r.map(mapping(CompetitionRankingData.Category::new)))
        )
        .from(COMPETITION)
        .where(COMPETITION.ID.eq(competitionId))
        .fetchOne(mapping(CompetitionRankingData::new));

【讨论】:

    【解决方案2】:

    看起来我可以调用 fetchOneInto(SomeRecordClass.class) 但这没有编译时间检查 JOOQ 的结果是否与 Record Class 的构造函数匹配。记录是指JDK16记录。

    public record CompanyAndPreferencesNice(CompanyRecord company,
                                            CompanyCo2ParameterRecord companyCo2Parameter,
                                            CompanyAccessCodeRecord companyAccessCode,
                                            Result<SubsidiaryRecord> subsidiaries,
                                            Result<CompanyAreaPreferenceRecord> companyAreaPreferences,
                                            Result<CompanySubareaPreferenceRecord> companySubareaPreferences,
                                            Result<ManifestDocumentPreferenceRecord> documentPreferences,
                                            Result<ServiceCompanyPreferenceRecord> serviceCompanyPreferences) {}
    
    
        return dslContext.get()
                .select(
                        COMPANY_CO2_PARAMETER.company(),
                        COMPANY_CO2_PARAMETER,
                        COMPANY_ACCESS_CODE,
                        multiset(
                                selectFrom(SUBSIDIARY)
                                        .where(SUBSIDIARY.COMPANY_ID.eq(companyId).and(SUBSIDIARY.ACTIVE.isTrue()))),
                        multiset(
                                selectFrom(COMPANY_AREA_PREFERENCE)
                                        .where(COMPANY_AREA_PREFERENCE.COMPANY_ID.eq(companyId).and(COMPANY_AREA_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(COMPANY_SUBAREA_PREFERENCE)
                                        .where(COMPANY_SUBAREA_PREFERENCE.COMPANY_ID.eq(companyId).and(COMPANY_SUBAREA_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(MANIFEST_DOCUMENT_PREFERENCE)
                                        .where(MANIFEST_DOCUMENT_PREFERENCE.COMPANY_ID.eq(companyId).and(MANIFEST_DOCUMENT_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(SERVICE_COMPANY_PREFERENCE)
                                        .where(SERVICE_COMPANY_PREFERENCE.COMPANY_ID.eq(companyId).and(SERVICE_COMPANY_PREFERENCE.DELETED.isFalse()))
                        ))
                .from(COMPANY_CO2_PARAMETER, COMPANY)
                .leftJoin(COMPANY_ACCESS_CODE).on(COMPANY_ACCESS_CODE.COMPANY_ID.eq(companyId))
                .where(COMPANY.ID.eq(companyId))
                .and(COMPANY_CO2_PARAMETER.COMPANY_ID.eq(companyId))
                .fetchOneInto(CompanyAndPreferencesNice.class);
    

    我也可以调用 fetchOne 返回一个类型安全的元组,然后将其作为唯一值传递到 JDK 16 记录中,如下所示......

    public record CompanyAndPreferences(
            org.jooq.Record8<CompanyRecord, CompanyCo2ParameterRecord, CompanyAccessCodeRecord, Result<SubsidiaryRecord>, Result<CompanyAreaPreferenceRecord>, Result<CompanySubareaPreferenceRecord>, Result<ManifestDocumentPreferenceRecord>, Result<ServiceCompanyPreferenceRecord>> jooqRecord) {
    }
        final var record = dslContext.get()
                .select(
                        COMPANY_CO2_PARAMETER.company(),
                        COMPANY_CO2_PARAMETER,
                        COMPANY_ACCESS_CODE,
                        multiset(
                                selectFrom(SUBSIDIARY)
                                        .where(SUBSIDIARY.COMPANY_ID.eq(companyId).and(SUBSIDIARY.ACTIVE.isTrue()))),
                        multiset(
                                selectFrom(COMPANY_AREA_PREFERENCE)
                                        .where(COMPANY_AREA_PREFERENCE.COMPANY_ID.eq(companyId).and(COMPANY_AREA_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(COMPANY_SUBAREA_PREFERENCE)
                                        .where(COMPANY_SUBAREA_PREFERENCE.COMPANY_ID.eq(companyId).and(COMPANY_SUBAREA_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(MANIFEST_DOCUMENT_PREFERENCE)
                                        .where(MANIFEST_DOCUMENT_PREFERENCE.COMPANY_ID.eq(companyId).and(MANIFEST_DOCUMENT_PREFERENCE.DELETED.isFalse()))),
                        multiset(
                                selectFrom(SERVICE_COMPANY_PREFERENCE)
                                        .where(SERVICE_COMPANY_PREFERENCE.COMPANY_ID.eq(companyId).and(SERVICE_COMPANY_PREFERENCE.DELETED.isFalse()))
                        ))
                .from(COMPANY_CO2_PARAMETER, COMPANY)
                .leftJoin(COMPANY_ACCESS_CODE).on(COMPANY_ACCESS_CODE.COMPANY_ID.eq(companyId))
                .where(COMPANY.ID.eq(companyId))
                .and(COMPANY_CO2_PARAMETER.COMPANY_ID.eq(companyId))
                .fetchOne();
        var companyAndPreferences = new CompanyAndPreferences(record);
    

    这更冗长,但会提供编译时检查。如果我更改查询结果类型,它会给出编译错误。

    【讨论】:

      猜你喜欢
      • 2018-05-19
      • 2010-10-23
      • 1970-01-01
      • 2022-11-08
      • 1970-01-01
      • 2013-10-18
      • 2023-03-25
      • 2012-11-19
      • 2016-10-01
      相关资源
      最近更新 更多