Loading

mybatis resultMap collection聚合String

背景

  • 主表index_dict_data

    img

  • 内容表index_dict_cn_name

    img

  • 期望输出数据结构:即联表之后根据indexId聚合,然后将cnName字段聚合到一个List<String>

    [
        {
            "indexId": "pageCrashNum",
            "cnNames": ["崩溃数","崩溃数"]
        },
        {
            "indexId": "pageCrashRate",
            "cnNames": ["崩溃率","崩溃率"]
        },
        {
            "indexId": "pageCrashUserNum",
            "cnNames": ["崩溃用户数","崩溃用户数"]
        }
    ]
    

配置

mapper.xml

<resultMap id="dictMap" type="com.wf.indexmetrics.IndexMetricsDictionary">
    <result column="indexId" property="indexId"/>
    <collection property="cnNames" javaType="list" ofType="java.lang.String">
        <!--虽然配置多个字段, 但是只会返回第一个, 但是聚合的时候会加入其他字段作为key-->
        <result column="cnName"/>
        <!--必须有唯一id, 否则对于相同的cnName为只保留一个-->
        <result column="cnNameId"/>
    </collection>
</resultMap>

<select id="getIndexMetricsList" resultMap="dictMap">
    SELECT
    tidd.index_id as indexId,
    tidd.dimension as dimension,
    cn.cn_name as cnName,
    cn.id as cnNameId
    FROM
    index_dict_data tidd
    LEFT JOIN index_dict_cn_name cn ON cn.index_id = tidd.index_id
    <where>
        and tidd.index_id in
        <foreach collection="indexKeys" open="(" separator="," close=")" item="item">
            #{item}
        </foreach>
    </where>
</select>

源码解析

  • org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyNestedResultMappings
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
    boolean foundValues = false;
    for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
        final String nestedResultMapId = resultMapping.getNestedResultMapId();
        if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
            try {
                final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
                final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
                if (resultMapping.getColumnPrefix() == null) {
                    // try to fill circular reference only when columnPrefix
                    // is not specified for the nested result map (issue #215)
                    Object ancestorObject = ancestorObjects.get(nestedResultMapId);
                    if (ancestorObject != null) {
                        if (newObject) {
                            linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
                        }
                        continue;
                    }
                }
                // rowKey实际为-2048015495:-685734919:com.sf.dev.mapper.IndexMetricsDictNewMapper.mapper_resultMap[dictMap]_collection[cnNames]:cnName:崩溃率:cnNameId:1008
                final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
                // combinedKey实际为-381970743:-2436525477:com.sf.dev.mapper.IndexMetricsDictNewMapper.mapper_resultMap[dictMap]_collection[cnNames]:cnName:崩溃率:cnNameId:1008:-1750790558:-229051733:com.sf.dev.mapper.IndexMetricsDictNewMapper.dictMap:metricsKey:pageCrashRate:dimension:%
                final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
                // 此处通过combinedKey判断是否已存在值, 如果只有cnName而没有cnNameId就会判断已存在, 在后面的逻辑就不会再加入到List
                Object rowValue = nestedResultObjects.get(combinedKey);
                boolean knownValue = rowValue != null;
                instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
                if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
                    rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
                    if (rowValue != null && !knownValue) {
                        // 把cnName add到List
                        linkObjects(metaObject, resultMapping, rowValue);
                        foundValues = true;
                    }
                }
            } catch (SQLException e) {
                throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
            }
        }
    }
    return foundValues;
}

问题

  • 起初没有配置cnNameId,保持唯一性,导致相同的cnName只保留了1个,实际应该保留2个

参考

posted @ 2022-12-19 18:52  FynnWang  阅读(873)  评论(0编辑  收藏  举报