mybatis中 一对多(collection)、多对一(association)的一些处理方式

目录

实体类:

通过SQL角度解决

一对多:查询指定用户共创建了那些文章类型

集合-collection(1:n)的使用:

处理方式一:查询条件嵌套

说明:

测试及结果:

处理方式二:查询结果嵌套

 说明:

测试及结果:

多对一:查询指定类型的创建者

关联-association(n:1)的使用

处理方式一:查询条件嵌套】

 测试及结果:

处理方式二:查询结果嵌套

测试及结果: 

当然也可通过代码角度来解决

 测试及结果:


传送门:

springboot整合mybatis

一对多和多对一是出于角度的不同,若 用户:该用户创建的文章类型 是一对多。

那反过来 该用户创建的文章类型:用户便是多对一。

实体类:

/**
 * @author Alex
 * 用户实体类
 */
@Data
public class IUser {

    private String userName;
    private String email;
    private String passWord;
    private Date birth;
    private int gender;

    /**
     *  user:type =1:n
     */
    private List<IType> types;
}
@Data
public class IType {

    /**
     * 文章类型名称
     */
    private String name;

    /**
     *  type:user = n:1
     */
    private IUser user;

}

通过SQL角度解决

一对多:查询指定用户共创建了那些文章类型

在IUserMapper.java接口创建查询用户的方法、并在IUserMapper.xml中实现这个接口方法。

    /**
     *查询指定用户及所创建的文章
     */
    IUser queryUser(int uId);

集合-collection(1:n)的使用:

处理方式一:查询条件嵌套

    <resultMap id="userMap" type="com.example.demo.domain.entity.IUser">
        <result column="user_name" property="userName"/>
        <collection property="types" javaType="ArrayList" column="u_id" select="queryTypeByUid"/>
    </resultMap>

    <resultMap id="typeMap" type="com.example.demo.domain.entity.IType">
        <result column="type_name" property="name"/>
    </resultMap>

    <select id="queryUser" resultMap="userMap">
        select u_id,user_name from t_user where u_id =#{uId}
    </select>

    <select id="queryTypeByUid" resultMap="typeMap">
        select type_name from t_type where user_id = #{id}
    </select>

说明:

  •  userMap是queryUser方法的查询结果的字段映射。
  • 从queryUser的查询结果中取到u_id,作为queryTypeByUid的查询条件。
  • javaType是指定IUser实体中、types的类型。
  • column是指定IUser的主键字段。

测试及结果:

    @Test
    public void testQueryUserById(){
        userMapper.queryUser(81);
    }

==>  Preparing: select u_id,user_name from t_user where u_id =?
==> Parameters: 81(Integer)
<==    Columns: u_id, user_name
<==        Row: 81, 李四
====>  Preparing: select type_name from t_type where user_id = ?
====> Parameters: 81(Integer)
<====    Columns: type_name
<====        Row: 诗歌
<====        Row: 小说
<====        Row: 散文
<====      Total: 3
<==      Total: 1

处理方式二:查询结果嵌套

将用户表join 类型表,对查询得到的结果进行字段映射

    <resultMap id="userMap2" type="com.example.demo.domain.entity.IUser">
        <result property="userName" column="user_name"/>
        <collection property="types" javaType="ArrayList" ofType="IType">
            <result property="name" column="type_name"/>
        </collection>
    </resultMap>
    <select id="queryUser2" resultMap="userMap2">
        select tu.user_name,tt.type_name
            from t_user tu  join t_type tt on tu.u_id=tt.user_id
            and tu.u_id=#{uId}
    </select>

 说明:

  • ofType指定list中属性的类型。

测试及结果:

    @Test
    public void testQueryUserById(){
        userMapper.queryUser2(81);
    }

==>  Preparing: select tu.user_name,tt.type_name from t_user tu join t_type tt on tu.u_id=tt.user_id and tu.u_id=?
==> Parameters: 81(Integer)
<==    Columns: user_name, type_name
<==        Row: 李四, 诗歌
<==        Row: 李四, 小说
<==        Row: 李四, 散文
<==      Total: 3

多对一:查询指定类型的创建者

在ITypeMapper.java接口创建查询类型的方法,并在ITypeMapper.xml中实现这个接口方法。

    /**
     * 查询指定文章及创建它用户
     */
    IType queryType(Integer tId);

关联-association(n:1)的使用

处理方式一:查询条件嵌套】

先查类型表,得到userId,再拿userId去用户表找用户名。

    <resultMap id="typeMap" type="com.example.demo.domain.entity.IType">
        <result property="name" column="type_name"/>
        <association property="user" javaType="IUser"  column="user_id"  select="queryUserById">
            <result property="userName" column="user_name"/>
        </association>
    </resultMap>

    <resultMap id="userMap" type="com.example.demo.domain.entity.IUser">
        <result property="userName" column="user_name"/>
    </resultMap>

    <select id="queryUserById" resultMap="userMap">
            select user_name from t_user where u_id =#{userId}
    </select>

    <select id="queryType" resultMap="typeMap">
        select user_id,type_name from t_type where t_id =#{tId}
    </select>
    

 测试及结果:

  @Test
    public void testQueryTypeById(){
        typeMapper.queryType(10);
    }

==>  Preparing: select user_id,type_name from t_type where t_id =?
==> Parameters: 10(Integer)
<==    Columns: user_id, type_name
<==        Row: 81, 诗歌
====>  Preparing: select user_name from t_user where u_id =?
====> Parameters: 81(Long)
<====    Columns: user_name
<====        Row: 李四
<====      Total: 1
<==      Total: 1

处理方式二:查询结果嵌套

类型表和用户表关联。根据类型ID来取值;

  <resultMap id="typeMap2" type="com.example.demo.domain.entity.IType">
        <result property="name" column="type_name"/>
        <association property="user" javaType="IUser" column="user_id">
            <result property="userName" column="user_name"/>
        </association>
    </resultMap>

    <select id="queryType2" resultMap="typeMap2">
        select tt.type_name,tu.user_name
                from t_user tu join t_type tt on tu.u_id = tt.user_id
                and tt.t_id =#{tId}
    </select>

测试及结果: 

  @Test
    public void testQueryTypeById(){
        typeMapper.queryType2(10);
    }

==>  Preparing: select tt.type_name,tu.user_name from t_user tu join t_type tt on tu.u_id = tt.user_id and tt.t_id =?
==> Parameters: 10(Integer)
<==    Columns: type_name, user_name
<==        Row: 诗歌, 李四
<==      Total: 1


当然也可通过代码角度来解决

类似查询条件嵌套、但是在程序是两个相互独立的方法。是实现功能解耦的一个思路。

比如:查询user_name="李四"创建的文章类型名称。

                1) 先通过用户表访问表拿到用户ID。

                2)通过用户ID去访问类型表取到类型名称。

根据提供的条件查询用户

    /**
     *根据提供的条件查询用户
     */
    IUser queryUser3(IUser user);
    <resultMap id="userMap4" type="com.example.demo.domain.entity.IUser">
        <result property="uId" column="u_id"/>
        <result property="userName" column="user_name"/>
    </resultMap>
    <select id="queryUser3" resultMap="userMap4" parameterType="com.example.demo.domain.entity.IUser">
        select user_name, u_id from t_user
            <where>
                <if test="userName != null">
                    and user_name = #{userName}
                </if>
                <if test="uId !=null">
                    and u_id =#{uId}
                </if>
            </where>
    </select>

 根据提供的条件查询文章类型

    /**
     * 根据提供的条件查询文章类型
     */
    List<IType> queryType3(IType type);
    <resultMap id="typeMap3" type="com.example.demo.domain.entity.IType">
        <result property="name" column="type_name"/>
        <result property="userId" column="user_id"/>
    </resultMap>

    <select id="queryType3" resultMap="typeMap3" parameterType="com.example.demo.domain.entity.IType">
        select type_name,user_id from t_type
        <where>
            <if test="userId !=null">
              and  user_id = #{userId}
            </if>
            <if test="name !=null">
              and  type_name = #{name}
            </if>
            <if test="tId !=null">
               and t_id =#{tId}
            </if>
        </where>
    </select>

 测试及结果:

    /**
     * 输出李四及其创建的文章类型
     */
    @Test
    public void testQueryUserByName(){

    // 1、 先通过用户名查询用户信息---->得到用户ID
        IUser queryUser = new IUser();
        queryUser.setUserName("李四");
        IUser user = userMapper.queryUser3(queryUser);

        // 2、通过用户ID得到该用户创建的所有类型
        IType type = new IType();
        type.setUserId(user.getUId());
        List<IType> types = typeMapper.queryType3(type);

        List<String> strings = new ArrayList<>();
        types.forEach(item->{
            strings.add(item.getName());
        });

        //3、输出
        HashMap<String,List<String>> userMap = new HashMap<>();
        userMap.put(user.getUserName(),strings);

        System.out.println("userMap:"+userMap);

    }

执行SQL:

==>  Preparing: select user_name, u_id from t_user WHERE user_name = ?
==> Parameters: 李四(String)
<==    Columns: user_name, u_id
<==        Row: 李四, 81
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1de08775]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b895e76] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1948456514 wrapping com.mysql.cj.jdbc.ConnectionImpl@3e998033] will not be managed by Spring
==>  Preparing: select type_name from t_type WHERE user_id = ?
==> Parameters: 81(Integer)
<==    Columns: type_name
<==        Row: 诗歌
<==        Row: 小说
<==        Row: 散文
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b895e76]

结果:
 userMap:{李四=[诗歌, 小说, 散文]}

    /**
     * 输出编号为10的类型名称及其创建者
     */

    @Test
    public void testQueryTypeByTId(){
        // 1、先访问类型表拿到user_id
        IType queryType = new IType();
        queryType.setTId(10);
        List<IType> types = typeMapper.queryType3(queryType);
        if(!CollectionUtils.isEmpty(types)){
            IType type = types.get(0);
            IUser queryUser = new IUser();
            queryUser.setUId(type.getUserId());
        // 2、再访问用户表拿到用户信息
            IUser user = userMapper.queryUser3(queryUser);

        //   3、输出

            HashMap<String, String> typeMap = new HashMap<>();
            typeMap.put(type.getName(),user.getUserName());

            System.out.println("typeMap:"+typeMap);
        }

    }

==>  Preparing: select type_name,user_id from t_type WHERE t_id =?
==> Parameters: 10(Integer)
<==    Columns: type_name, user_id
<==        Row: 诗歌, 81
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1cc93da4]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64688978] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1297242263 wrapping com.mysql.cj.jdbc.ConnectionImpl@433ae0b0] will not be managed by Spring
==>  Preparing: select user_name, u_id from t_user WHERE u_id =?
==> Parameters: 81(Integer)
<==    Columns: user_name, u_id
<==        Row: 李四, 81
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64688978]
typeMap:{诗歌=李四}

 放在map中是为便于理解,实际情况直接通过对应的的setter方法给属性赋值,前端拿到对象后、或取List中的字段、或取对应属性的值。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值