Mybatis 子查询 - mybatis select child object

最近有这样一个需求,查询符合条件的 3D图纸包 的信息以及该图纸包里包含的图纸的信息,这显然是查询一个对象的子属性,于是有了本文,本文将讲述 mybatis 子查询,即 return a list inside an object from mybatis.

mybatis 子查询主要用到 collection 属性,如下:

<resultMap id="pageResultMap" type="xxx.xxx.xxx.xxx">
    <id column="id" jdbcType="VARCHAR" property="id"/>
    <result column="title" jdbcType="VARCHAR" property="title"/>
    <result column="image" jdbcType="VARCHAR" property="image"/>
    <collection property="paperList" javaType="java.util.List" ofType="java.util.Map"
                column="{packageId=id}" select="paperList" fetchType="eager">
    </collection>
</resultMap>

这里,xxx.xxx.xxx.xxx 是具体的类名,关系到公司的实际业务,此处略过,下面的 ofType 也可以是实际的类名,如果是实际的类名,那么可能所有的字段将都会返回了,如果不想要返回所有的字段,可以设为 java.util.Map,下面细说下 collection 属性

property 表示这个对象的字段的名称,即子查询的结果在 xxx.xxx.xxx.xxx 里对应的变量的名称,为方便起见 下文称 xxx.xxx.xxx.xxx 为 Parent.java ,则 Parent.java 应该如下:

public class Parent {

    private List<HashMap<String, Object>> paperList;

    public List<HashMap<String, Object>> getPaperList() {
        return paperList;
    }

    public void setPaperList(List<HashMap<String, Object>> paperList) {
        this.paperList = paperList;
    }
}

这里忽略了其他别的变量哦,主要是 变量名 paperList 要和 collection 里面的 property 对应。

javaType 表示这个子查询返回值的类型,即 paperList 的类型,这里是 java.util.List,而 ofType 指的是映射到 paperList 里面的元素的类型,这里是 java.util.Map,关键是 column,它实际是传参,你可以这么理解,column="{传入子查询的参数名 = 对应的Parent里面的字段名, ...}" ,这里传入子查询的参数名是 packageId,对应 Parent 里的 id,下面看下具体的 sql

<select id="paperList" parameterType="java.util.Map" resultType="java.util.Map">
    select id as paperId, title as paperTitle, url
    from xxx
    where id in (select paperId from xxx2 where packageId = #{packageId, jdbcType=VARCHAR})
</select>

<select id="findByCourseId" resultMap="pageResultMap">
    select title, image, coursePackageId, id from xxx3
    <if test="courseId != null">
        where coursePackageId = #{courseId, jdbcType=VARCHAR}
    </if>
    order by orderNum desc
    <if test="start!=null and pageSize!=null">limit #{start,jdbcType=INTEGER},
        #{pageSize,jdbcType=INTEGER}
    </if>
</select>

这里 xxx 表示图纸的数据库,xxx2 是图纸和图纸包的关联数据库,xxx3 是图纸包数据库,该查询(findByCourseId)的查询结果可能如下:

{
  "retCode": 1,
  "retMsg": "获取成功",
  "retObj": {
    "total": 1,
    "list": [
      {
        "coursePackageId": "Code",
        "id": "PPG-190247670630060032",
        "image": "url",
        "title": "图纸包标题",
        "paperList": [
          {
            "paperId": "PP-190349796114960384",
            "paperTitle": "title",
            "url": "paperLink"
          }
        ]
      }
    ]
  }
}

当然,你可以修改 Parent.java 里的 map 为具体的类型,比如 我这里为 3D图纸的类型,然后修改 ofType 以及 resultType 为具体的类型,这样你拿到的数据类型也是对的,但是返回的数据可能有冗余,并且不支持起别名哦。总体而言,我还是觉得用 map 更好点,但是如果返回的数据你还要操作,比如读取值,那么使用具体的类型可能更好。

2019.11.04 更新 :添加  fetchType="eager" 如果不添加 可能会出现:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.HashMap["data"]->java.util.ArrayList[0]->xxx.xxx.xxx_$$_jvst4a2_0["handler"])

如果出现这个错误,那么将

<collection property="paperList" javaType="java.util.List" ofType="java.util.Map" column="{packageId=id}" select="paperList"> </collection>

改为:

<collection property="paperList" javaType="java.util.List" ofType="java.util.Map" column="{packageId=id}" select="paperList" fetchType="eager"> </collection>

 

即可。

本博客若无特殊说明则由 full-stack-trip 原创发布
转载请点名出处:全栈之旅 > Mybatis 子查询 - mybatis select child object
本文地址:https://www.kpromise.top/mybatis-select-child-object/

发表评论

电子邮件地址不会被公开。 必填项已用*标注