Mybatis 多对多映射的小问题

问题

ORM 映射中,一对多,多对多是非常常见的方式。但是由于场景使用没有这么多,到今天我才发现这个问题。

配置映射关系,使字段与 DO 类解耦,方便维护。但是为了方便管理和控制,我就在一个 .java 文件中写了两个 VO 类。

@ToString
@Setter(value = AccessLevel.PUBLIC)
@Getter(value = AccessLevel.PUBLIC)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class CategoryVO {

    private Long cid;
    private Long pid;
    private Integer level;
    private Integer sortNo;
    private String cname;
    private java.sql.Timestamp created;
    private java.sql.Timestamp updated;

    private List<Word> words;
}
@ToString
@Setter(value = AccessLevel.PUBLIC)
@Getter(value = AccessLevel.PUBLIC)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(value = JsonInclude.Include.NON_NULL)
class Word {
    private Long id;
    private Long hotWordId;
    private Long categoryId;
    private String keyword;
    private Integer source;
    private Integer sortNo;
    private Integer isDeleted;
    private java.sql.Timestamp created;
    private java.sql.Timestamp updated;
}

它们的关系也非常简单,可以直接看出,一个类目(分类)对应多组 HotWord(热词)。所以在 resultMap 中为了图快我就直接把属性一个个映射数据库的 column 了。

<resultMap id="result" type="{hape}.common.orm.model.vo.CategoryVO">
  			<!-- 相同的列名id -->
        <id column="id" jdbcType="INTEGER" property="cid"/>
        <result column="parent_id" jdbcType="INTEGER" property="pid"/>
        <result column="name" jdbcType="VARCHAR" property="cname"/>
        <result column="level" jdbcType="INTEGER" property="level"/>
        <result column="sort_no" jdbcType="INTEGER" property="sortNo"/>
        <collection property="words" ofType="{hape}.common.orm.model.vo.Word">
            <!-- 相同的列名id -->
            <id column="id" jdbcType="INTEGER" property="id"/>
            <result column="hotword_id" jdbcType="INTEGER" property="hotWordId"/>
            <result column="category_id" jdbcType="INTEGER" property="categoryId"/>
            <result column="keyword" jdbcType="VARCHAR" property="keyword"/>
            <result column="source" jdbcType="TINYINT" property="source"/>
            <result column="sort_no" jdbcType="INTEGER" property="sortNo"/>
            <result column="is_deleted" jdbcType="TINYINT" property="isDeleted"/>
            <result column="created" jdbcType="TIMESTAMP" property="created"/>
            <result column="updated" jdbcType="TIMESTAMP" property="updated"/>
        </collection>
</resultMap>

但是实际结果却并不是一个包含了多个子结构的对象,而是只有一个 words 对象,究其原因,原来是因为 colum 列名有重复,都存在一个相同的 id。

解决办法

你可以选择干掉其中一个 id,或者在使用 SQL 语句中加入别名加以区分,当字段较多的时候就会比较麻烦。我这里把字段都加上了 w_ 区分。

<select id="selectHotWordByCategoryId" parameterType="int" resultMap="result">
        select
        <!-- 为什么要as "w_"呢?因为两张表的colum有相同的名称会出现问题,不然就只能查出子表的一条而不是多条了 -->
            t1.*, t2.id as w_id, t2.hotword_id as w_hotword_id, t2.keyword as w_keyword,
            t2.source as w_source, t2.sort_no as w_sort_no, t2.created as w_created, t2.updated as w_updated
        from
            xunfei_category t1
        left join
            xunfei_hotword t2
        on
            t1.id = t2.category_id
        where
            t1.id = #{id}
        and
            t2.is_deleted = 0
        order by
            t2.sort_no,
            t2.updated desc
   </select>

然后在 resultMap 中修改成改后的别名就 OK 啦。

<resultMap id="result" type="{hape}.common.orm.model.vo.CategoryVO">
    <id column="id" jdbcType="INTEGER" property="cid"/>
    <result column="parent_id" jdbcType="INTEGER" property="pid"/>
    <result column="name" jdbcType="VARCHAR" property="cname"/>
    <result column="level" jdbcType="INTEGER" property="level"/>
    <result column="sort_no" jdbcType="INTEGER" property="sortNo"/>
    <collection property="words" ofType="{hape}.common.orm.model.vo.Word">
        <id column="w_id" jdbcType="INTEGER" property="id"/>
        <result column="w_hotword_id" jdbcType="INTEGER" property="hotWordId"/>
        <result column="w_category_id" jdbcType="INTEGER" property="categoryId"/>
        <result column="w_keyword" jdbcType="VARCHAR" property="keyword"/>
        <result column="w_source" jdbcType="TINYINT" property="source"/>
        <result column="w_sort_no" jdbcType="INTEGER" property="sortNo"/>
        <result column="w_is_deleted" jdbcType="TINYINT" property="isDeleted"/>
        <result column="w_created" jdbcType="TIMESTAMP" property="created"/>
        <result column="w_updated" jdbcType="TIMESTAMP" property="updated"/>
    </collection>
</resultMap>
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 Google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    138 引用 • 402 回帖 • 698 关注
  • 映射
    2 引用
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    269 引用 • 547 回帖 • 1 关注
  • 多对多
    1 引用
回帖
请输入回帖内容...