myBatis中的语句映射几种特别方式

对于myBatis中的高级映射通常会使用resultMap参数,而非使用resultType参数,虽然对于大多数的查询来说resultType会更常用,其实这两种方式都是比较好使用的,只通常来说,当配置为resultType参数,所做的映射查询通常会简单一些,而使用resultMap参数要相对复杂一些,不如果不是太复杂使用resultMap没有太大的意义,因为它需要多配置一个resutMap映射结点对象,但有时你会发现,在查询时90%字段来源于一个表,而只有相别字段来源于另一个表,此时如果使用resultMap其实就有些得不偿失,但有些开发人却不知道怎样使用较简单的方法来处理它,其实很很简单,具体可以查看下面的配置:

	<select id="getLogs" parameterType="CoreLog" resultType="CoreLog">
		select<include refid="fieldAsProperty" />,bb.cract_Name AS "strMap.cractName"
		from core_log aa 
		left join core_account bb on aa.crlog_cract_uuid = bb.cract_uuid
		<where>
			<include refid="conditionA" />
		</where>
		order by crlog_cdate desc
	</select>

上面其实就是使用比较简单的方法将数据库列映射到了bean的一个属性strMap.cractName上面,这是一个带有链式的语法,如果采用resultMap写法可能就会比较麻烦,例如: 

	<resultMap type="CoreLog" id="fieldMapperEX" extends="fieldMapper">
		<result property="strMap.cractName" column="cractName"/>
	</resultMap>
	<select id="getLogs" parameterType="CoreLog" resultMap="fieldMapperEX">
		select<include refid="fieldAsProperty" />,bb.cract_Name AS cractName
		from core_log aa 
		left join core_account bb on aa.crlog_cract_uuid = bb.cract_uuid
		<where>
			<include refid="conditionA" />
		</where>
		order by crlog_cdate desc
	</select>

这里需要修正说明一下:对于上面的第一种写法是不完全正确的,这可能是当前myBatis3.0.5不够完善的地方这里需要说明下这两种写法的原理,其实终这两种写法最终的落脚点在第二种方法,第一种方法只所不需要这种配置是因为它通过指定resultType与列名称进行了一种反射不区分大小写的适配,但这是种适配现在还有不完善的地方,主要体现在链式语法中间含有一些非javaBean类型(例如上面的Map类型),则框架进行推测就会出错,具体逻辑可以查看以下源代码.

  protected boolean applyAutomaticMappings(ResultSet rs, List<String> unmappedColumnNames, MetaObject metaObject) throws SQLException {
    boolean foundValues = false;
    for (String columnName : unmappedColumnNames) {
      final String property = metaObject.findProperty(columnName);
      if (property != null) {
        final Class propertyType = metaObject.getSetterType(property);
        if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
          final TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(propertyType);
          final Object value = typeHandler.getResult(rs, columnName);
          if (value != null) {
            metaObject.setValue(property, value);
            foundValues = true;
          }
        }
      }
    }
    return foundValues;
  }
  public String findProperty(String propName) {
    return objectWrapper.findProperty(propName);
  }
  public String findProperty(String name) {
    return metaClass.findProperty(name);
  }
  public String findProperty(String name) {
    StringBuilder prop = buildProperty(name, new StringBuilder());
    return prop.length() > 0 ? prop.toString() : null;
  }
  private StringBuilder buildProperty(String name, StringBuilder builder) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      String propertyName = reflector.findPropertyName(prop.getName());
      if (propertyName != null) {
        builder.append(propertyName);
        builder.append(".");
        MetaClass metaProp = metaClassForProperty(propertyName);
        metaProp.buildProperty(prop.getChildren(), builder);
      }
    } else {
      String propertyName = reflector.findPropertyName(name);
      if (propertyName != null) {
        builder.append(propertyName);
      }
    }
    return builder;
  }
	public String findPropertyName(String name) {
		return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
	}

通过源代码的追踪你会发现缺陷出在org.apache.ibatis.reflection.Reflector#findPropertyName,它只考虑了标准的javaBean反射,对于Map类型的数据没有进行考虑,当然它是指在链式语法的中间存在Map型数据才会不能正确的返回属性的名称,或或许在将来的某个版本中可以支持类似Map类型数据的链式语法. 

但是对于javaBean成员字段属性则不存在这样的问题,例如:

<select id="getMultiOrgsByUsr" resultType="CoreAccount" parameterType="CoreAccount">
		select 
		cc.cract_name as cractName, 
		cc.cract_Unid as cractUnid,
		cc.cract_Uuid as cractUuid,
		cc.cract_crorg_uuid as cractCrorgUuid,
		aa.cramo_unid as "coreAccountOrganiz.cramoUnid",
		bb.crorg_full_name as "coreOrganization.crorgFullName",
		bb.crorg_uuid as "coreOrganization.crorgUuid"
		from core_account_organiz aa 
		left join core_organization bb on aa.cramo_crorg_uuid = bb.crorg_uuid
		left join core_account cc on aa.cramo_cract_uuid = cc.cract_uuid
		where aa.cramo_cract_uuid = #{cractUuid}
	</select>

上面的coreAccountOrganiz与coreOrganization都属于CoreAccount的成员字段,将其中的几个数据库列字段映射到成员中的某几个字段段上,从上面的分析可以看出对从一张表查询所有字段,而从另外的一张表中查询少量字段可以优先使用resultType参数是一种最适合的方法,对于resultMap配置,通常对于单表映射开发人员都会使用代码生成工具生成,对于这种情况,如果希望映射出类似于Hibernate的效果,如果还使用resultType参数就会有些不好做,需要写很多SQL,如果使用resultMap参数就可以共享单表的映射定义,具体参考下面的配置:

这上CoreAccount的映射配置:

	<resultMap id="fieldMapper" type="CoreAccount">
		<id property="cractUnid" column="cractUnid" /><!--标识UNID-->
		<result property="cractUuid" column="cractUuid" /><!--标识UUID-->
		<result property="cractLevelCode" column="cractLevelCode" /><!--层级编码-->
		<result property="cractCrorgUuid" column="cractCrorgUuid" /><!--默认机构-->
		<result property="cractIdNumber" column="cractIdNumber" /><!--身份证号-->
		<result property="cractMobile" column="cractMobile" /><!--手机号码-->
		<result property="cractJobNumber" column="cractJobNumber" /><!--职位代码-->
		<result property="cractLevel" column="cractLevel" /><!--帐户级别-->
		<result property="xxxxx" column="xxxx" /><!--帐户代码-->
	</resultMap>

下面是CoreAccountOrganiz映射配置:

	<resultMap id="fieldMapper" type="CoreAccountOrganiz">
		<id property="cramoUnid" column="cramoUnid" /><!--标识UNID-->
		<result property="cramoCractUuid" column="cramoCractUuid" /><!--帐户UUID-->
		<result property="cramoCrorgUuid" column="cramoCrorgUuid" /><!--机构部门UUID-->
		<result property="cramoOrd" column="cramoOrd" /><!--排序号-->
		<result property="cramoExtCrorgUuid" column="cramoExtCrorgUuid" /><!--机构UUID-->
		<result property="cramoExt1" column="cramoExt1" /><!--扩展字段1-->
		<result property="cramoExt2" column="cramoExt2" /><!--扩展字段2-->
	</resultMap>

如果这两张表要进行关联查询映射,并且希望在CoreAccount对象中获取一个完整的CoreAccountOrganiz成员对象,则可以使用下面的方式:

<resultMap type="CoreAccount" id="fieldMapperEX" extends="fieldMapper">
	<association property="coreOrganization" resultMap="com.risen.core.dao.mapper.ICoreOrganizationMapper.fieldMapper" />
	<association property="coreAccountOrganiz" resultMap="com.risen.core.dao.mapper.ICoreAccountOrganizMapper.fieldMapper" />
</resultMap>

这上面是映射两个成员对象,上面只是列举了一个,此时你就可以使用

	<select id="getAccountByOrg" parameterType="CoreAccount" resultMap="fieldMapperEX">
		select 
		<include refid="fieldAsProperty" />,
		<include refid="com.risen.core.dao.mapper.ICoreOrganizationMapper.fieldAsProperty" />,
		<include refid="com.risen.core.dao.mapper.ICoreAccountOrganizMapper.fieldAsProperty" />
		from core_account_organiz aa
		join core_account bb on aa.cramo_cract_uuid = bb.cract_uuid
		join core_organization cc on bb.cract_crorg_uuid = cc.crorg_uuid
		where aa.cramo_crorg_uuid = #{cractCrorgUuid} and bb.cract_status != 2
		<if test="cractLevel != null" >
			and cract_level=#{cractLevel}
		</if>
		order by aa.cramo_ord
	</select>

来进行映射查询,而这里使用的是resultMap查询,此如果你需要映射字段就不应该在语句中来完成,而应该在fieldMapperEX对象中去定义,例如先前使用bb.cract_Name AS "strMap.cractName"这种语法基本是不起作用的因为在fieldMapperEX对象并没有定义strMap.cractName这样的字段映射,如果此时你还希望进行个别字段的映射还是需要在fieldMapperEX对象定义:strMap.cractName的映射,例如:

<resultMap type="CoreAccount" id="fieldMapperEX" extends="fieldMapper">
	<result property="strMap.cractName" column="xxxxxxx" />
	<association property="coreOrganization" resultMap="com.risen.core.dao.mapper.ICoreOrganizationMapper.fieldMapper" />
	<association property="coreAccountOrganiz" resultMap="com.risen.core.dao.mapper.ICoreAccountOrganizMapper.fieldMapper" />
</resultMap>

其实从这里对比着看你会发现result标签与association标签之间的其实差不多,只是association定义属类似于定义了一个前缀而已,上面也可以将strMap对象映射到另一个resultMap对象而在另一个resultMap对象不去映射字段:

<resultMap type="CoreLog" id="fieldMapperEX" extends="fieldMapper">
	<result property="cractName" column="cractName"/>
</resultMap>


此时你的strMap前缀就可以被取消掉了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值