对于一对一,一对多,多对一,多对多的关联查询,Mybatis-Plus 在处理时,需要编写关联查询方法及配置resultMap,并且书写SQL。

为了简化这种操作,可以注解来简化。

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

mprelation源码地址  :

     github:     https://github.com/dreamyoung/mprelation.git

     gitee:        https://gitee.com/dreamyoung/mprelation.git

mprelation_demo 地址  :

    github:      https://github.com/dreamyoung/mprelation_demo.git 

    gitee:        https://gitee.com/dreamyoung/mprelation_demo.git

POM引用 :

<dependency>
<groupId>com.github.dreamyoung</groupId>
<artifactId>mprelation</artifactId>
<version>0.0.3.1-RELEASE</version>
</dependency>

注解工具使用优缺点:

优点:

使用简单,通过在实体类上添加@OneToOne / @OneToMany@ManyToOne@ManyToMany  等注解即可。

1对1、1对多、多对1、多对多映射时,可以不再写SQL及XML配置文件,免去配置冗长的<resultMap>的麻烦。

Service层及Mapper层不需要再添加 getLinkById 、 selectLinkById   之类的方法来关联映射

重写过的ServiceImpl各种内置的查询方法都自动关联查询,非内置方法可以调用autoMapper相关方法进行自动或手动关联

解决关联处理的1+n问题

缺点:

目前只针对SqlSession/Mappe形式有效(ActiveRecord形式暂未涉及修改,也没有测试)

非事务下, 1个连接(1个SqlSession)只执行一条SQL,而自动获取每个关联属性的sql都会创建1~2个SqlSession(并执行1~2条SQL)。

★ 可通过配置事务,让所有关联属性都使用同一个SqlSession(此时非延迟加载的关联属性无论有多少都可以同在一个事务一个SqlSession中执行,而每个延迟加载的关联属性,在自动触发时还会创建一次SqlSession,但可以配置为非自动触发---即实体类上标注@AutoLazy(false)或没有标注该注解(默认),之后通过initialize方法在事务范围内的一个SqlSession中同时加载多个延迟加载的属性。)

使用注意点:

ServiceImpl内置的业务查询,配置事务管理,减少SqlSession的创建。

实体上可用注解@AutoLazy(true/false)来标注是否自动触发延迟加载

★  true或无值的话,则获取延迟的关联属性时自动关联。

★  false或者不标注该注解的话,需要手动通过initialize()方法对延迟的关联属性进行获取,否则不会自动关联获取,此时关联为空

如果可以,不使用延迟加载(延迟加载的使用是在SqlSession关闭后执行的,需要重新创建SqlSession)。

如果确实需要延迟加载,可使用ServiceImpl   AutoMapper 相关的initialize方法一次性加载所有需要的被延迟的属性(只需要创建额外的一个SqlSession,毕竟SqlSession之前已经关闭)

注解使用:

一对多(多对一) :

Company实体类中配置:

@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;
}

Man实体类中配置:

@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)

一对一:

Woman实体类配置:

@Data
public class Woman {
@TableId(value = "woman_id")
private Long id;
private String name;

//一对一
@TableField("lao_gong_id")
private Long laoGongId; @TableField(exist = false)
@OneToOne //一对一默认为立即加载,即@Lazy(false)或此时不标注
@JoinColumn(name = "lao_gong_id", referencedColumnName = "man_id")
private Man laoGong;
}

Man实体类配置:

@Data
public class Man {
@TableId(value = "man_id")
private Long id;
private String name; //一对一
@TableField("lao_po_id")
private Long laoPoId; @TableField(exist = false)
@OneToOne
@JoinColumn(name = "lao_po_id", referencedColumnName = "woman_id")
private Woman laoPo;
}

一对一表结构:(实际可以减少一方)  woman: (woman_id,  name,   lao_gong_id)           man: (man_id,   name,   lao_po_id)

多对多:

Course实体类配置:

@Data
public class Course {
@TableId(value = "course_id")
private Long id;
private String name; //多对多
@TableField(exist = false)
@ManyToMany //多对多默认为延迟加载,即@Lazy(true)或此时不标注
@JoinTable(targetMapper = StudentCourseMapper.class) //第三方命名为StudentCourseMapper或CourseStudentMapper时@JoinTable注解一般可省略
@JoinColumn(name = "course_id", referencedColumnName = "course_id")
@InverseJoinColumn(name = "child_id", referencedColumnName = "student_id")
private List<Child> students;
}

Child实体类配置:

@Data
public class Child {
@TableId("child_id")
private Long id;
private String name; //多对多
@TableField(exist = false)
@ManyToMany
@JoinTable(targetMapper=StudentCourseMapper.class)
@JoinColumn(name = "child_id", referencedColumnName = "student_id")
@InverseJoinColumn(name = "course_id", referencedColumnName = "course_id")
private List<Course> courses;
}

StudenCourse中间类(多对多必须要有,如果命名为StudentCourse或CourseStudent,则上边的@JoinTable可省略):

@Data
public class StudentCourse {
//可以有也可以无此ID
private Long id; @TableField("student_id")
private Long studentId; @TableField("course_id")
private Long courseId;
}

多对多表结构:course: (course_id,  name)          child: (child_id,   name)       student_course:(id,   student_id,    course_id)

mprelation 关联查询,使用过程:   

1.   POM中引入mprelation:

<dependency>
<groupId>com.github.dreamyoung</groupId>
<artifactId>mprelation</artifactId>
<version>0.0.3.1-RELEASE</version>
</dependency>

配置 AutoMapper (只要是扫描被注解的实体类)

@Configuration
public class AutoMapperConfig {
@Bean
public AutoMapper autoMapper() {
return new AutoMapper(new String[] { "demo.entity","demo.bean" }); //配置实体类所在目录(可多个,暂时不支持通过符*号配置)
}
}

2.   在实体类中配置注解(更多的注解配置见上边注解部分,这里只列出其中一个)

@Data
@AutoLazy  //对标注了@Lazy(true)的延迟关联属性,当进行获取时启动自动触发加载,否则(即标注为false或没有该注解),须手动触发加载(如initialize等方法)再进行获取。
public class Man { 
    @TableId(value = "man_id")
private Long id;
private String name; private Long laoPoId;
@TableField(exist = false)
@OneToOne
@JoinColumn(name = "lao_po_id", referencedColumnName = "woman_id")
private Woman laoPo;

@TableField("company_id")
private Long companyId; @TableField(exist = false)
@ManyToOne
@JoinColumn(name = "company_id", referencedColumnName = "company_id")private Company company;

@TableField(exist = false)
@OneToMany
@JoinColumn(name = "man_id", referencedColumnName = "lao_han_id")
private List<Child> waWa;

@TableField(exist = false)
@OneToMany
@JoinColumn(name = "man_id", referencedColumnName = "man_id")
@Lazy(false)
private Set<Tel> tels; }

3.   在Service层、Mapper层的使用,见下面:

以下是基于Mybatis-Plus官方示例修改而来的测试程序:

通过继承工具类重写过的IService /  ServiceImpl   会自动执行关联映射, 无须再写gettLinkById之类的方法(可以使得各实现类没有任何方法):

mapper接口:

public interface ManMapper extends BaseMapper<Man> {}

service接口:

public interface IManService extends IService<Man> {}  // IService为重写过的同名接口

Service实现:

@Service
public class ManServiceImpl extends ServiceImpl<ManMapper, Man> implements IManService {} // ServiceImpl为重写过的同名接口

测试调用:

public class ServiceTest {
@Autowired

ManService manService; @Test
public void t_man_serviceImpl() {
Man man = manService.getById(1); // 原Mybatis-Plus的ServiceImpl的各种查询,被重写过后,都可以自动关联,
System.out.println(man);
}
}

结果输出:

Man(
id=1,
name=程序猿小明,
laoPoId=1,
laoPo=Woman(id=1, name=程序猿小明老婆, laoGongId=1, laoGong=null, waWa=null),
companyId=1,
company=Company(id=1, name=百度, employees=null),
waWa=[
Child(id=1,name=xxx1,lao_han_id=null, laoHan=null, lao_ma_id=null, laoMa=null, courses=null),
Child(id=2,name=xxxx2, lao_han_id=null, laoHan=null, lao_ma_id=null, laoMa=null, courses=null)
],
tels=[
Tel(id=1, tel=139xxxxxx, manId=1, laoHan=null),
Tel(id=4, tel=159xxxxxx, manId=1, laoHan=null),
Tel(id=2, tel=137xxxxxx, manId=1, laoHan=null)
]
)

如需需要对其关联属性对象的关联属性进行自动加载,可以继续使用AutoMapper对象的mapperEntity、mapperEntityList、mapperEntitySet、mapperEntityPage来操作:

比如想获取(填充)waWas 的关联,则:

List waWas=man.getWaWas();
autoMapper.mapperEntityList(waWas);

AutoMapper类中的几个常用方法说明:

mapperEntity(entity)                                            可以对一个实体类,实现自动关联。

mapperEntityList(entity_list)                                可以对一个实体类List,实现自动关联。

mapperEntitySet(entity_set)                                可以对一个实体类Set,实现自动关联。

mapperEntityCollection(entity_list_or_set)          可以对一个实体类Set或List,实现自动关联。

mapperEntityPage(entity_page)                          可以对一个实体类Page,实现自动关联。

initialize(entity/entityList/entitySet/entityPage,    OneOrMoreLazyPropertyName ...)

可以对一个实体类/实体类List/实体类Set/实体类Page,在事务范围内,手动立即触发其各个被@Lazy(true)标注的关联属性。

该方法在重写过的ServiceImpl内也存在(供Controller层调用来加载延迟关联的属性)。

AutoMapper在重写过的ServiceImpl类中已经自动注入可用(名为autoMapper),其它情况也可以手动注入:

public class MPRTest2 {
@Autowired
AutoMapper
autoMapper; @Resource
private ManMapper manMapper; @Test
public void t_man() {
Man man = manMapper.selectById(1L);
autoMapper.mapperEntity(man);
System.out.println(man);
} }

 最新版本POM:

<dependency>
<groupId>com.github.dreamyoung</groupId>
<artifactId>mprelation</artifactId>
<version>0.0.3.1-RELEASE</version>
</dependency>

github:   https://github.com/dreamyoung/mprelation

 

MyBatis-Plus不写任何resultMap和SQL执行一对一、一对多、多对多关联查询的更多相关文章

  1. MyBatis 一对多,多对一关联查询的时候Mapper的顺序

    要先写association,然后写collection:这是由DTD决定的: <resultMap ...> <association ...> </associati ...

  2. mybatis实战教程二:多对一关联查询(一对多)

    多对一关联查询 一.数据库关系.article表和user表示多对一的关系 CREATE TABLE `article` ( `id` ) NOT NULL AUTO_INCREMENT, `user ...

  3. mybatis多对多关联查询

    多对多关系 一个学生可以选多门课程,而一门课程可以由多个学生选择,这就是一个典型的多对多关联关系.所谓多对多关系,其实是由两个互反的一对多关系组成.即多对多关系都会通过一个中间表来建立,例如选课表.学 ...

  4. mybatis 14: 多对一关联查询

    业务背景 根据订单id查询订单的信息,以及该订单所属的客户的基本信息(不包括该客户自己的订单信息) 两张数据表 客户表 订单表 实体类 客户实体类:Customer private Integer i ...

  5. 精尽 MyBatis 源码分析 - SqlSession 会话与 SQL 执行入口

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  6. mybatis一对多关系的关联查询

    问题描述:实现两张表的关联查询 学生表: 班级表: 要实现学生管理信息中有所在班级的名称,即如下图所示 1.对应学生表的pojo类写全班级表中的字段(适用于要连接的表字段较少的情况) sql语句直接在 ...

  7. mybatis多对多关联查询——(十)

    1.需求 查询用户及用户购买商品信息. 2     sql语句 查询主表是:用户表 关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表: orders.orderdetail. ...

  8. mybatis实现多表一对一,一对多,多对多关联查询

    原文:https://blog.csdn.net/m0_37787069/article/details/79247321 1.一对一关键字:association作用:针对pojo对象属性的映射  ...

  9. mybatis 一对多和多对一关联查询

    首先  数据库量表之间字段关系(没有主外键) studentmajor表的id字段对应student表里major字段 两个实体类 package com.model; import java.uti ...

随机推荐

  1. [LC] 117. Populating Next Right Pointers in Each Node II

    Given a binary tree struct Node { int val; Node *left; Node *right; Node *next; } Populate each next ...

  2. Grails Controller - respond 方法

    基本用法 官方文档:http://docs.grails.org/latest/ref/Controllers/respond.html 为当前 respond 语句所在 action 所对应的页面返 ...

  3. xml_class来自 phpcms

    <?php class xml{ var $parser; var $document; var $stack; var $data; var $last_opened_tag; var $is ...

  4. 抽样分布|t分布|中心极限定理|点估计|矩估计|最大似然法|

    生物统计与实验设计-统计学基础-2&区间估计-1 正态分布参数:均值和方差 其中,选择1d是因为好算:通常,95%区分大概率事件和小概率事件, 当总体是正态分布时,可以利用常用抽样分布估计出样 ...

  5. zabbix的MariaDB数据库改变存储位置

    #创建 mkdir /公司缩写/mysql   #停止数据库服务 systemctl status mariadb.service systemctl stop mariadb.service   # ...

  6. node.js 和 npm/cnpm/nrm 的安装

    node.js 和 npm/cnpm/nrm 的安装 安装 node.js.去 官网 下载,下载 LTS 版本的.安装时一路点确定,不要改动任何设置. 在 git-bash 或是 cmd 下,输入 n ...

  7. 吴裕雄--天生自然HTML学习笔记:HTML 框架

    通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面. iframe语法: <iframe src="URL"></iframe> 该URL指向不同的网 ...

  8. Java如何打印日志

    以下为<正确的打日志姿势>学习笔记. 什么时候打日志 1.程序出现问题,只能通过 debug 功能来定位问题,很大程度是日志没打好.良好的系统,通过日志就能进行问题定位. 2.if-els ...

  9. shell的循环嵌套语法

    测试shell的循环嵌套语法 [root@localhost test]# vi Xunhuanqiantao.sh #!/bin/bash #程序功能描述: # 测试循环嵌套 #作者:孤舟点点 #版 ...

  10. 12月18日风险投资速递:Facebook收购实时体育数据提供商Sport Stream

    国内公司 1.手游公司成都掌沃无限获得近千万元天使投资 成都掌沃无限成立于2013年,是一家新成立的手机游戏开发商,创始人及CEO张涛拥有超过10年的游戏行业从业经验和连续创业经历,其首款游戏产品为& ...