<resultMap id="postLiteMap2NestedWithSelect" type="org.apache.ibatis.domain.blog.BlogLite">
<id column="blog_id" property="id" />
<collection property="posts" ofType="org.apache.ibatis.domain.blog.PostLite">
<constructor>
<arg javaType="org.apache.ibatis.domain.blog.PostLiteId" column="{id=id}" select="selectPostLiteId" />
<arg javaType="_int" column="blog_id"/>
</constructor>
</collection>
</resultMap>
<mapper namespace="org.apache.ibatis.domain.blog.mappers.PostMapper">
<resultMap id="postLiteIdMap" type="org.apache.ibatis.domain.blog.PostLiteId">
<constructor>
<idArg javaType="_int" column="id"/>
</constructor>
</resultMap><select id="selectPostLite2NestedWithSelect" resultMap="postLiteMap2NestedWithSelect">
select id, 1 as blog_id from post where blog_id is not null
</select>
<select id="selectPostLiteId" resultMap="postLiteIdMap">
select ${id} as id from (values(0)) as t
</select>查询
List<BlogLite> posts = session.selectList("org.apache.ibatis.domain.blog.mappers.PostMapper.selectPostLite2NestedWithSelect");
下面通过代码看看Mybatis是如何处理的
public ResultMapping buildResultMapping(
Class<?> resultType,
String property,
String column,
Class<?> javaType,
JdbcType jdbcType,
String nestedSelect,
String nestedResultMap,
String notNullColumn,
String columnPrefix,
Class<? extends TypeHandler<?>> typeHandler,
List<ResultFlag> flags,
String resultSet,
String foreignColumn,
boolean lazy) {
//
Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
//类型处理器
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
//解析混合列
List<ResultMapping> composites = parseCompositeColumnName(column);
//构建ResultMapping
return new ResultMapping.Builder(configuration, property, column, javaTypeClass)
.jdbcType(jdbcType)
//对嵌套查询ID进行namespace处理
.nestedQueryId(applyCurrentNamespace(nestedSelect, true))
//对嵌套ResultMap进行namespace处理
.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true))
.resultSet(resultSet)
.typeHandler(typeHandlerInstance)
.flags(flags == null ? new ArrayList<ResultFlag>() : flags)
.composites(composites)
.notNullColumns(parseMultipleColumnNames(notNullColumn))
.columnPrefix(columnPrefix)
.foreignColumn(foreignColumn)
.lazy(lazy)
.build();
}
private List<ResultMapping> parseCompositeColumnName(String columnName) {
List<ResultMapping> composites = new ArrayList<ResultMapping>();
//如果columnName不为null 同时colunmnName中含有"=" 或者含有","号
if (columnName != null && (columnName.indexOf('=') > -1 || columnName.indexOf(',') > -1)) {
//分割字符串
StringTokenizer parser = new StringTokenizer(columnName, "{}=, ", false);
while (parser.hasMoreTokens()) {
//获取属性
String property = parser.nextToken();
//获取列
String column = parser.nextToken();
//构建复合的ResultMapping
ResultMapping complexResultMapping = new ResultMapping.Builder(
configuration, property, column, configuration.getTypeHandlerRegistry().getUnknownTypeHandler()).build();
composites.add(complexResultMapping);
}
}
return composites;
}
至此可以发现{id=id}被解析为了一个复合resultMapping那么在使用的时候又是如何处理的呢?
//获取嵌套查询构造参数的值
private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
//嵌套查询ID
final String nestedQueryId = constructorMapping.getNestedQueryId();
//嵌套查询MappedStatement
final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
//嵌套查询参数类型
final Class nestedQueryParameterType = nestedQuery.getParameterMap().getType();
//获取嵌套查询入参值
final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
Object value = null;
if (nestedQueryParameterObject != null) {
final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
final Class targetType = constructorMapping.getJavaType();
final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
value = resultLoader.loadResult();
}
return value;
}
private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class parameterType, String columnPrefix) throws SQLException {
//如果是复合映射
if (resultMapping.isCompositeResult()) {
return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
} else {
return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
}
}
private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class parameterType, String columnPrefix) throws SQLException {
//创建参数对象
final Object parameterObject = instantiateParameterObject(parameterType);
final MetaObject metaObject = configuration.newMetaObject(parameterObject);
boolean foundValues = false;
//遍历复合结果映射
for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
//获取参数类型
final Class propType = metaObject.getSetterType(innerResultMapping.getProperty());
final TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(propType);
final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
// 如果参数值不为null则设置到参数对象
if (propValue != null) {
metaObject.setValue(innerResultMapping.getProperty(), propValue);
foundValues = true;
}
}
return foundValues ? parameterObject : null;
}
此时获取到的入参 id值为1 ,同样在其它嵌套查询中也可以使用复合映射
<resultMap id="addressMapper"
type="org.apache.ibatis.submitted.column_prefix.Address">
<constructor>
<idArg column="id" javaType="int" />
<arg column="state" javaType="string" />
</constructor>
<result property="city" column="city" />
<result property="hasPhone" column="has_phone" />
<association property="stateBird" select="selectStateBird"
column="state" />
<association property="zip" select="selectZip"
column="{state=state,city=city}" />
<association property="phone1" select="selectPhone"
column="phone1_id" />
<association property="phone2" select="selectPhone"
column="phone2_id" />
<discriminator column="addr_type" javaType="int">
<case value="1"
resultType="org.apache.ibatis.submitted.column_prefix.AddressWithCaution">
<result property="caution" column="caution" />
</case>
</discriminator>
</resultMap>
本文来自网易实践者社区,经作者张伟授权发布。