首页 > 技术文章 > Mybatis——Plus :表与表之间的关系:1对多和多对一

gtnotgod 2021-02-25 22:34 原文

Mybatis——plus我大致整理出两种方案:

第一种:第三方mybatis-plus 插件,注解式开发

Mybatis-Plus-Relation ( mprelation ) : mybatis-plus 一对一、一对多、多对一、多对多的自动关联查询,注解方式。

<dependency>
     <groupId>com.github.dreamyoung</groupId>
     <artifactId>mprelation</artifactId>
     <version>0.0.3.2-RELEASE</version> 
</dependency>
  • 使用简单,通过在实体类上添加@OneToOne / @OneToMany / @ManyToOne / @ManyToMany 等注解即可*

使用要点

使用注意点:
       非ServiceImpl内置的业务查询,配置事务管理,减少SqlSession的创建。
       实体上可用注解@AutoLazy(true/false)来标注是否自动触发延迟加载,该注解只针对需要延迟的属性。
       ★true或无值的话,则获取延迟的关联属性时自动关联。但每一个延迟属性的获取都消耗一个SqlSession。适合于只有一个延迟属性的情况。
       ★false或者不标注该注解的话,需要手动通过initialize()方法对延迟的关联属性进行获取,否则不会自动关联获取,此时关联为空。适合于有多个延迟属性的情况。
       如果可以,不使用延迟加载(延迟加载的使用是在SqlSession关闭后执行的,需要重新创建SqlSession)。
       如果确实需要延迟加载,可使用ServiceImpl 或  AutoMapper 相关的initialize方法一次性加载所有需要的被延迟的属性(只需要创建额外的一个SqlSession,毕竟SqlSession之前已经关闭)

具体使用

@Data
public class Company {
    @TableId(value = "company_id")
    private Long id;
    private String name;
    
    //一对多
    @TableField(exist = false)
    @OneToMany //一对多默认为延迟加载,即@Lazy/@Lazy(true)/或此时不标注
    @JoinColumn(name="company_id",referencedColumnName = "company_id")//@TableId与一方相关属性中@TableField名称保持一致时@JoinColumn可省略
    private Set<Man> employees;
}
@Data
public class Man {

    @TableId(value = "man_id")
    private Long id;
    private String name;

    //多对一
    @TableField("company_id")
    private Long companyId;
    
    @TableField(exist = false)
    @ManyToOne //多对一默认为立即加载,即@Lazy(false)或此时不标注
    @JoinColumn(name = "company_id", referencedColumnName = "company_id") //相关的@TableField与多方的@TableId名称一致时@JoinColumn可省略
    private Company company;
}

一对多(多对一)表结构: company: (compnay_id, name) man: (man_id, name, company_id)

方式二:java实体类加入 关联对象(可以是单个,也可以是集合)

package com.gton.person.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 *
 * </p>
 *
 * @author GuoTong
 * @since 2020-12-24
 */
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "StudentActivity对象", description = "活动表")
public class StudentActivity implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "活动表的ID")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;

    @ApiModelProperty(value = "活动名称")
    private String activityName;

    /**
     * 在添加的时候插入时间
     */
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 在修改或者第一次添加的时候自动填充
     */
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @ApiModelProperty(value = "活动结束时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endTime;

    @ApiModelProperty(value = "活动详情")
    private String activityDesc;

    @ApiModelProperty(value = "活动发起人")
    private String openUserId;

    @ApiModelProperty(value = "是否开启加权投票")
    private Integer isShow;

    @ApiModelProperty(value = "活动LOGO地址")
    private String activityImage;

    /**
     * 参加活动的密码
     */
    @ApiModelProperty(value = "参加活动的密码")
    private String activityPassword;

    //:@TableField(exist = false)表示该属性不为数据库表字段,但又是必须使用的。反之必须使用
    @ApiModelProperty(value = "关系:1:oo")
    @TableField(exist = false)
    private List<StudentActivityItems> items;
}

通过 collection 就是查询的几个表里面的字段名不能有重复的 可以别名
   <!--手动数据库字段和实体类映射-->
    <resultMap id="resMap" type="com.gton.person.entity.StudentActivity">
        <id column="id" property="id"></id>
        <result property="activityName" column="activity_name"></result>
        <result property="createTime" column="create_time"></result>
        <result property="updateTime" column="update_time"></result>
        <result property="endTime" column="end_time"></result>
        <result property="activityDesc" column="activity_desc"></result>
        <result property="openUserId" column="open_user_id"></result>
        <result property="isShow" column="is_show"></result>
        <result property="activityImage" column="activity_image"></result>
        <!--一对多,方式一{就是查询的几个表里面的字段名不能有重复的}-->
        <collection property="items" ofType="com.gton.person.entity.StudentActivityItems">
            <id column="item_id" jdbcType="VARCHAR" property="id"/>
            <result column="activity_id" jdbcType="INTEGER" property="activityId"/>
            <result column="count" jdbcType="VARCHAR" property="count"/>
            <result column="item_desc" jdbcType="VARCHAR" property="itemDesc"/>
            <result column="head_img" jdbcType="VARCHAR" property="headImg"/>
            <result column="item_name" jdbcType="TIMESTAMP" property="itemName"/>
        </collection>
    </resultMap>
<!--one To Many||注意一对多关系不能有相同的列,如果有相同的取别名,然后映射别名就可以了-->
    <select id="getByOneToMany" resultMap="resMap">
         select a.*,i.id as item_id,i.count,i.item_desc,i.item_name,i.head_img
         from student_activity_items i,student_activity a
         where i.activity_id = #{activeId}
         and i.activity_id = a.id
    </select>
然后这样做会把mybatis-plus原本的自动映射方式破坏:,会报错坏sql

解决方式 :::忽视该字段与数据库字段映射, @TableField(exist = false)

  //:@TableField(exist = false)表示该属性不为数据库表字段,但又是必须使用的。反之必须使用
    @ApiModelProperty(value = "关系:1:oo")
    @TableField(exist = false)
    private List<StudentActivityItems> items;

就这样搞定了

推荐阅读