MyBatis Collection Notes - Association query, recursive query, multi-field association

    The Collection tag of mybatis is often used for cascading queries or recursive queries. Now, a pseudo example is used to briefly illustrate the key points in use:

    First, list three tables and give a scenario:

1. Role table t_role( id,name )  
2. Menu table t_menu( id, name, pid ) The menu table is a pid that points to the id of the upper-level menu, so it is a tree table
3. Role menu association table t_role_menu( role_id, menu_id ) Role and menu one-to-many association

The java object is as follows:

// menu object
public class Menu {
  private Long id;
  private String name;
  private Long pid;
  private List<Menu> subMenus;//Submenu collection
}

// character object
public class Role {
  private Long id;
  private String name;
  private List<Menu> menus;//Associative menu collection
}

to elicit the following query scenario:

1. Simple association query: query the role based on the role id, and the set of menus associated with the role;

    The mapper xml file is configured as follows:

<!--1, query the role based on the primary key, and its associated menu -->
<select id="selectRoleById" parameterType="Long" resultMap="RoleResultMap">
	select * from t_role where id = #{id}
</select>

<!--2, role result mapping -->
<resultMap id="RoleResultMap" type="Role">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <collection property="menus"  column="id" ofType="Menu" select="selectMenuByRoleId"/>
</resultMap>

<!--3, according to the role id, query the menu collection -->
<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
	select a.* from t_menu a
	join t_role_menu b on a.id = b.menu_id and b.role_id= #{roleId} <!--roleId This variable name can be written casually -->
</select>

<!--4, menu result mapping -->
<resultMap id="MenuResultMap" type="Menu">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="pid" jdbcType="BIGINT" property="name" />
</resultMap>

    In this way, the "selectRoleById" method is used to query the specified role and the associated menu set. The calling order has been arranged according to the serial number 1234, and the association relationship is marked with the same color. There are two points to note:

    1. In step 2, column="id" in the collection tag, the id is the column in the role query result mapping, not the property;

    2, Step 3, parameter #{roleId}, this name can be arbitrarily started;

    Through the above example, the menu associated with the role can be queried, but the submenu set of each menu object is null, because there is no submenu of the query menu, the following scenario is introduced: recursive query.


Second, recursive query (special association query): query the menu tree according to the menu id, and call yourself

    The mapper xml file is configured as follows:

<!--1, according to the primary key query menu -->
<select id="selectMenuTreeById" parameterType="Role" resultMap="MenuResultMap">
	select * from t_menu where id = #{id}
</select>

<!--2, menu result mapping -->
<resultMap id="MenuResultMap" type="Menu">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="pid" jdbcType="BIGINT" property="name" />
    <collection property="subMenus"  column="id" ofType="Menu" select="selectSubMenuByPid"/>
</resultMap>

<!--3, query id query menu -->
<select id="selectSubMenuByPid" parameterType="Role" resultMap="MenuResultMap">
	select * from t_menu where pid = #{pid}
</select>

    In this way, the "selectMenuTreeById" method is called to complete the call of the menu tree, which is one step less result mapping than the above related query, because the mapping results of the parent query and the sub query are the same. The point of attention is also here.


3. Multi-field association: Change the recursive query above a little bit, instead of querying the menu tree by the id of the menu, but querying the menu tree of the specified role, how should I change it?

<!--1, query menu based on character id -->
<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
	select a.* from t_menu a
	join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
</select>

    Let's change the method of the first step, the parameter becomes the role id, and associate it through the association table, is this all right? The answer is: NO!

    Because this can only ensure that the root menu is associated with the role, the submenu below cannot be guaranteed to be associated with the role, and the corresponding push query also needs to be associated, so it leads to the situation of "multi-field association", the complete mapper xml The file configuration is as follows:

<!--1, query menu based on character id -->
<select id="selectMenuByRoleId" parameterType="Long" resultMap="MenuResultMap">
	select a.*, b.role_id
	from t_menu a
		join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
</select>

<!--2, menu result mapping -->
<resultMap id="MenuResultMap" type="Menu">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="pid" jdbcType="BIGINT" property="name" />
    <!--Associative parameters, not related to java entities-->
    <result column="role_id" jdbcType="BIGINT" />
    <collection property="subMenus"  column="{pid=id,roleId=role_id}" ofType="Menu" select="selectSubMenuByPid"/>
</resultMap>

<!--3, query id query menu -->
<select id="selectSubMenuByPid" parameterType="java.util.Map" resultMap="MenuResultMap">
	select a.*, b.role_id
	from t_menu a
		join t_role_menu b on a.id = b.menu_id and b.role_id=#{roleId}
	where a.pid = #{pid}
</select>

The subquery also needs to be associated with the associated table, but there are a few points to note:

    1. It is necessary to find out the associated role id in the first step and put it in the result map. As shown in the second step, a result tag is added. The column is the role_id, but do not add the property (if it is actually needed, also It can be added, but this property needs to be added to the java object), it is not mapped to the java object, but only used as an associated field.

    2. It is necessary to add an associated field in the collection tag. The writing of multiple columns is as shown above. In the form of k=v, k is the parameter name, and v is the referenced result field (column instead of property). At the same time, in the subquery, the The parameter type needs to be changed to Map, and the parameter name cannot be written casually. It needs to be used according to the specified parameter name in the collection.


Let's talk about this first.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324884196&siteId=291194637