Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
520 views
in Technique[技术] by (71.8m points)

mybatis - Reusing dynamic sql fragments

Hei there, I'm working on a Primefaces app and as a persistence layer I chose Mybatis.

This is how a regular sql would look in my mapper:

<select id="getAllTransportUnit" resultMap="TransportUnitMap">
    SELECT * FROM SSLS_GUI.VW_TU
    <if test="( hasFilters == 'yes' ) and ( parameters != null )">
        <where>
            <foreach item="clause" collection="parameters" separator=" AND "
                open="(" close=")">
                UPPER(${clause.column}) ${clause.operator} #{clause.value}
            </foreach>
        </where>
    </if>
    <if test="sort == 'true'">
        ORDER BY ${sortField}
        <if test="sortOrder == 'DESC'"> DESC</if>
        <if test="sortOder == 'ASC'"> ASC</if>
    </if>
</select>

Almost all my queries use the dynamic sql part starting from the <if test...>. Is it possible to put it in a separate file and then reuse it all over my queries?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are several options how to reuse sql snippets.

SQL snippets and include

The first one is using include. Create separate mapper Common.xml:

<mapper namespace="com.company.project.common">
    <sql id="orderBy>
      <if test="sort == 'true'">
        ORDER BY ${sortField}
        <if test="sortOrder == 'DESC'"> DESC</if>
        <if test="sortOder == 'ASC'"> ASC</if>
      </if>
    </sql>


    <sql id="filters">
     <if test="( hasFilters == 'yes' ) and ( parameters != null )">
      <where>
        <foreach item="clause" collection="parameters" separator=" AND "
            open="(" close=")">
            UPPER(${clause.column}) ${clause.operator} #{clause.value}
        </foreach>
     </where>
    </if>
  </sql>
</mapper>

And the use it in other mappers MyMapper.xml:

<select id="getAllTransportUnit" resultMap="TransportUnitMap">
  SELECT * FROM SSLS_GUI.VW_TU
  <include refid="com.company.project.common.filters"/>
  <include refid="com.company.project.common.orderBy"/>
</select>

To avoid duplicating namespace in every include you can create shortcut snippets in MyMapper.xml:

<sql id="orderBy">
  <include refid="com.company.project.common.orderBy"/> 
</sql>

<select id="getAllTransportUnit" resultMap="TransportUnitMap">
  SELECT * FROM SSLS_GUI.VW_TU
  <include refid="orderBy"/>
</select>

Mybatis-velocity macro

Another possible option is to use mybatis scripting. Using mybatis-velocity scripting engine you can define velocity macro and reusing it like this.

In Commons.xml:

<sql id="macros"
  #macro(filters)
    #if ( $_parameter.hasFilters )
      #repeat( $_parameter.parameters $clause "AND" " (" ")" )
        ${clause.column} ${clause.operator} @{clause.value}
      #end
    #end
  #end

  #macro(order_by)
  .. 
  #end
</sql>

In MyMapper.xml:

<select id="getAllTransportUnit" resultMap="TransportUnitMap">
  <include refid="macros"/>
  SELECT * FROM SSLS_GUI.VW_TU
  #filters()
  #order_by()
</select>

Including macros via sql snippet is not the most clean way to reuse macros. It is just an idea how this is used.

Much better option is to configure mybatis-velocity and specify what global macros are available. In this case there will be no need to do include of macros snippet and result query will be like this:

<select id="getAllTransportUnit" resultMap="TransportUnitMap">
  SELECT * FROM SSLS_GUI.VW_TU
  #filters()
  #order_by()
</select>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...