ibatis to mybatis.Part 2

在转换的过程中,陆续遇到了几个问题

jdbcType大小写问题

Build.xml
<replace dir="destination" includes="*.xml" token=":NUMERIC#" value=",jdbcType=NUMERIC#" encoding="UTF8"/>
<replace dir="destination" includes="*.xml" token=":TIMESTAMP#" value=",jdbcType=TIMESTAMP#" encoding="UTF8"/>
<replace dir="destination" includes="*.xml" token=":VARCHAR#" value=",jdbcType=VARCHAR#" encoding="UTF8"/>

jdbcType的大小写需要实现转换,另外需要添加更多的类型。

dynamic的转换缺失

默认的migrate.xslt没有对dynamic element做转换,需要新增转换逻辑。

首先确定dynamic element的定义,ibatis.dtd中可以找到

<!--Wrapper tag that allows for an overall prepend, open and close.-->
<!ELEMENT dynamic (#PCDATA | include | iterate | isParameterPresent | isNotParameterPresent | isEmpty | isNotEmpty | isNotNull | isNull | isNotEqual | isEqual | isGreaterThan | isGreaterEqual | isLessThan | isLessEqual | isPropertyAvailable | isNotPropertyAvailable)*>
<!ATTLIST dynamic
prepend CDATA #IMPLIED
open CDATA #IMPLIED
close CDATA #IMPLIED
>

然后将dynamic element的处理逻辑加入到migrate.xslt中。

migrate.xslt
<xsl:template match="dynamic">
    <xsl:element name="trim">
        <xsl:attribute name="prefix">
            <xsl:value-of select="@prepend" />
        </xsl:attribute>
        <xsl:attribute name="prefixOverrides">
            <xsl:text>and|or|,</xsl:text>
        </xsl:attribute>
        <xsl:value-of select="@open" />
        <xsl:apply-templates/>
        <xsl:value-of select="@close" />
    </xsl:element>  
</xsl:template>

效果如下:

ibatis source
<dynamic prepend=" where " close="and (1=1)">
  <isNotNull property="offerId" prepend="and">
    item_id=#offerId#
  </isNotNull>
</dynamic>

mybatis target
<trim prefix=" where " prefixOverrides="and|or|,">
  <if test="offerId != null">and
    item_id=#{offerId}
  </if>
</trim>


isNotEmpty的翻译错误

原先isNotEmpty的转换逻辑为:

<xsl:template match="isNotEmpty">
  <xsl:element name="if">
    <xsl:attribute name="test">
      <xsl:if test="substring-before(@property, '.')">
        <xsl:value-of select="substring-before(@property, '.')" /><xsl:text> != null and </xsl:text>
      </xsl:if>
      <xsl:value-of select="@property" /><xsl:text> != null and </xsl:text>
      <xsl:value-of select="@property" /><xsl:text>.size != 0</xsl:text>
    </xsl:attribute>
    <xsl:value-of select="@prepend" />
      <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

但是当遇到iterate类型时,直接!=”是会报错的。需要针对iterate类型,修改isNotEmpty的逻辑

<xsl:template match="isNotEmpty">
  <xsl:element name="if">
    <xsl:attribute name="test">
      <xsl:if test="substring-before(@property, '.')">
        <xsl:value-of select="substring-before(@property, '.')" /><xsl:text> != null and </xsl:text>
      </xsl:if>
      <xsl:value-of select="@property" /><xsl:text> != null and </xsl:text>
      <xsl:choose>
        <xsl:when test="child::node()[contains(name(), 'iterate')]">
          <xsl:value-of select="@property" /><xsl:text>.size != 0</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@property" /><xsl:text> != ''</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:value-of select="@prepend" />
      <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

最终的转换效果如下:

ibatis source
<isNotEmpty property="offerIds" prepend="and">
  item_id in
  <iterate property="offerIds" conjunction="," open="(" close=")">
    #offerIds[]#
  </iterate>
</isNotEmpty>

mybatis target
<if test="offerIds != null and offerIds.size != 0">and
  item_id in
  <foreach collection="offerIds" item="item" separator="," close=")" open="(">
    #{item}
  </foreach>
</if>

ibatis to mybatis.Part 1

目标

将ibatis的dynamic SQL,翻译为符合mybatis规范的SQL

两者区别

ibatis

官方文档
标签可以嵌套,具体包括以下几种:

  • Binary Conditional Elements
<isEqual prepend="AND"  property="status"  compareValue="Y">
MARRIED = 'TRUE'
</isEqual> 

  • Unary Conditional Elements
<isNotNull prepend="AND" property="order.id" >
  ORDER.ORDER_ID = #order.id#
</isNotEmpty>

  • Parameter Present Elements
<isParameterPresent prepend="AND">
  EMPLOYEE_TYPE = #empType#
</isParameterPresent>

  • Iterate Element
<select id="select-test" resultMap="MyTableResult" parameterClass="list">
select * from my_table where col_1 in
  <iterate open="(" close=")" conjunction=",">
   #[]#
  </iterate>
</select>

  • Simple Dynamic SQL Elements
<statement id="getProduct" resultMap="get-product-result">
  select * from PRODUCT order by $preferredOrder$
</statement>

mybatis

官方文档

  • if
<if test="title != null">
  AND title like #{title}
</if>
<if test="author != null and author.name != null">
  AND author_name like #{author.name}
</if>

  • choose (when, otherwise)
<choose>
  <when test="title != null">
    AND title like #{title}
  </when>
  <when test="author != null and author.name != null">
    AND author_name like #{author.name}
  </when>
  <otherwise>
    AND featured = 1
  </otherwise>
</choose>

  • trim (where, set)
<trim prefix="WHERE" prefixOverrides="AND |OR ">   ... </trim>
  • foreach
<foreach item="item" index="index" collection="list"
    open="(" separator="," close=")">
      #{item}
</foreach>

  • Direct substitution
<select id="selectByNetworkId" parameterType="java.util.Map" resultMap="userResult">
    select user_profile.user_profile_id,  user_profile.first_name
    from user_profile user_profile
    where  user_profile.network_id = #{network_id}  
    order by  user_profile.user_profile.first_name ${sortType}
</select>

方案

  1. 传参格式的转换
    • replace $id$ with ${id}
    • replace #id# with #{id}
    • replace xyz[] with item for use in iterators
  2. Element写法的转换
    • isNull -> object == null OR object.property == null
    • isNotNull -> object != null AND object.property != null
    • isNotEmpty -> object != null AND object.property != null AND object.property != ”
    • isEmpty -> object != null AND (object.property == null OR object.property == ”)
    • isGreaterThan -> property > value (number or another property)
    • isLessThan -> property < value (number or another property)
    • isEqual -> object != null AND object.property == value (number or another property)
    • isLessEqual -> object != null AND object.property <= value (number or another property)
    • iterate
  3. 无法转换的Element
    • dynamic
    • isPropertyAvailable
    • isNotPropertyAvailable
    • isNotParameterPresent
    • isParameterPresent

(to be continued ……)