我有一个用例,其中通过联接两个表ITEMITEM_DESCRIPTION构造结果。从那里开始,我准备了几列,然后将它们方便地转换为对象列表。在我的情况下,这些对象实际上是DTO对象,但是当然它们也可以是业务对象。

这就是我现在做的方式:

public Map<Long, List<StoreItemDTO>> getItems(Long storeId) {

    LOGGER.debug("getItems");

    // Get all item_ids for the store

    SelectHavingStep<Record1<Long>> where = this.ctx
        .select(STORE_ITEM.ID)
        .from(STORE_ITEM)
        .where(STORE_ITEM.STORE_ID.eq(storeId))
        // GROUP BY store_item.id
        .groupBy(STORE_ITEM.ID);

    // Get all store_item_details according to the fetched item_ids

    TableLike<?> storeItemDetails = this.ctx
        .select(
                STORE_ITEM_DETAILS.ID,
                STORE_ITEM_DETAILS.STORE_ITEM_ID,
                STORE_ITEM_DETAILS.NAME,
                STORE_ITEM_DETAILS.DESCRIPTION,
                STORE_ITEM_DETAILS.STORE_LANGUAGE_ID
                )
        .from(STORE_ITEM_DETAILS)
        .where(STORE_ITEM_DETAILS.STORE_ITEM_ID.in(where))
        .asTable("storeItemDetails");

    // Join the result and use

    Field<Long> itemIdField = STORE_ITEM.ID.as("item_id");

    Result<?> fetch = this.ctx
        .select(
                STORE_ITEM.ID.as("item_id"),
                itemIdField,
                storeItemDetails.field(STORE_ITEM_DETAILS.ID),
                storeItemDetails.field(STORE_ITEM_DETAILS.NAME),
                storeItemDetails.field(STORE_ITEM_DETAILS.DESCRIPTION),
                storeItemDetails.field(STORE_ITEM_DETAILS.STORE_LANGUAGE_ID)
                )
        .from(STORE_ITEM)
        .join(storeItemDetails)
        .on(storeItemDetails.field(STORE_ITEM_DETAILS.STORE_ITEM_ID).eq(STORE_ITEM.ID))
        .fetch();

    Map<Long, ?> groups = fetch.intoGroups(STORE_ITEM.ID);

    return null;
}


如您所见,结果应该是项目列表,其中每个项目都有一个使用不同语言的明细:

 StoreItemDTO
 - Long id
   // Maps language-id to item details
 - Map<Long, StoreItemDetails> itemDetails

 StoreItemDetails
 - Long id
 - String name
 - String description


我找不到会返回有用类型的intoGroups()版本。我可以想象有类似Map<Long, List<Record>>的东西,但我却无法做到。

但是,有一个intoGroups(RecordMapper<? super R, K> keyMapper)可能正是我想要的。如果映射器还允许我实际将结果记录转换为自定义对象,例如MyCustomPojo,那么我可以非常方便地检索和转换数据。我不知道这是否可行。就像是:

public static class MyCustomPojo {
    public Long itemId;
    // etc.
}

// ..

Map<Long, List<MyCustomPojo>> result = fetch.intoGroups(STORE_ITEM.ID, new RecordMapper<Record, List<MyCustomPojo>>() {
    @Override
    public List<MyCustomPojo> map(List<Record> record) {
        // 'record' is grouped by STORE_ITEM.ID
        // Now map each 'record' into every item of each group ..
        return resultList;
    }
});


但是不幸的是编译器只允许

fetch.intoGroups(new RecordMapper<Record, Result<?>>() {
    @Override
    public Result<?> map(Record record) {
        return null;
    }
});

最佳答案

经过一番摆弄之后,编译器被证明是可以做到的。

我不得不通过在匿名之外将生成的地图声明为final来“作弊”,实际上我并没有“使用” keyMapper参数,因为我只是返回了null

这是我想出的:

public Map<Long, StoreItemDTO> getItems(Long storeId) {

    // Get all item_ids for the store

    SelectHavingStep<Record1<Long>> where = this.ctx
        .select(STORE_ITEM.ID)
        .from(STORE_ITEM)
        .where(STORE_ITEM.STORE_ID.eq(storeId))
        .groupBy(STORE_ITEM.ID);

    // Get all store_item_details according to the fetched item_ids

    TableLike<?> storeItemDetails = this.ctx
        .select(
                STORE_ITEM_DETAILS.ID,
                STORE_ITEM_DETAILS.STORE_ITEM_ID,
                STORE_ITEM_DETAILS.NAME,
                STORE_ITEM_DETAILS.DESCRIPTION,
                STORE_ITEM_DETAILS.STORE_LANGUAGE_ID
                )
        .from(STORE_ITEM_DETAILS)
        .where(STORE_ITEM_DETAILS.STORE_ITEM_ID.in(where))
        .asTable("storeItemDetails");

    // Join the result and use

    final Field<Long> itemIdField = STORE_ITEM.ID.as("item_id");

    Result<?> fetch = fetch = this.ctx
        .select(
                itemIdField,
                storeItemDetails.field(STORE_ITEM_DETAILS.ID),
                storeItemDetails.field(STORE_ITEM_DETAILS.NAME),
                storeItemDetails.field(STORE_ITEM_DETAILS.DESCRIPTION),
                storeItemDetails.field(STORE_ITEM_DETAILS.STORE_LANGUAGE_ID)
                )
        .from(STORE_ITEM)
        .join(storeItemDetails)
        .on(storeItemDetails.field(STORE_ITEM_DETAILS.STORE_ITEM_ID).eq(STORE_ITEM.ID))
        .fetch();

    final Map<Long, StoreItemDTO> itemIdToItemMap = new HashMap<>();

    fetch.intoGroups(
            record -> {
                Long itemDetailsId = record.getValue(STORE_ITEM_DETAILS.ID);
                // ... sake of compactness

                StoreItemDetailsDTO storeItemDetailsDto = new StoreItemDetailsDTO();
                storeItemDetailsDto.setId(itemDetailsId);
                // ... sake of compactness

                Long itemId = record.getValue(itemIdField);

                StoreItemDTO storeItemDto = new StoreItemDTO();
                storeItemDto.setId(itemId);
                storeItemDto.getItemDetailsTranslations().put(languageId, storeItemDetailsDto);

                StoreItemDTO itemDetailsList = itemIdToItemMap.get(itemId);

                if(itemDetailsList == null) {
                    itemDetailsList = new StoreItemDTO();
                    itemIdToItemMap.put(itemId, itemDetailsList);
                }

                itemDetailsList.getItemDetailsTranslations().put(languageId, storeItemDetailsDto);

                return null;
            });

    return itemIdToItemMap;
}


由于我不确定这是否是最优雅的解决方案,因此我仍然愿意征求建议,并愿意接受任何可以优雅缩短此代码的答案-如果目前可以的话。 :)

10-06 06:45