Mybatis Plus 使用学习十 关联查询和级联查询

我们本节演示表关联查询和两个表一对一的级联查询。

两个表关联后,返回的结果我们有两种返回结果集的方式,一种是平铺方式,也就是两个表的字段都放到一个entity中;另一种是一个entity中持有另一个entity。

我们举例以班级表和学生表为例,一个班级对应多个学生,一个学生对应多个班级。

我们先来构造数据。

1、构造两个表,班级表和学生表


DROP TABLE IF EXISTS classz;

CREATE TABLE classz
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '班级名称',
	PRIMARY KEY (id)
);

DROP TABLE IF EXISTS student;

CREATE TABLE student
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	cid BIGINT(20),
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	PRIMARY KEY (id)
);

2、初始化表中数据

DELETE FROM classz;

INSERT INTO classz (id, name) VALUES
(1, '一年一班'),
(2, '一年二班');

DELETE FROM student;

INSERT INTO student (id, cid, name) VALUES
(1, 1,'小明'),
(2, 1,'小欧');

如果我们从学生的角度查询学生,并把学生对应的班级也关联出来,那么这两种方式的展示方式,我们先看第一种,平铺式的,也就是所有结果字段都在一个类中。

1、构造entity,用于保存结果

package com.itzhimei.mybatis.plus.model;

import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

/**
 * @Auther: www.itzhimei.com
 * @Description: 班级和学生entity
 */

@Data
public class ClasszAndStudent {
    private Long id;
    private String name;

    private Long stdId;
    private Long cid;
    private String stdName;
}

2、在mapper中构建一个查询方法,两个表关联,字段重名就命名别名,与entity对应上

package com.itzhimei.mybatis.plus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzhimei.mybatis.plus.model.Classz;
import com.itzhimei.mybatis.plus.model.ClasszAndStudent;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description:
 */
public interface ClasszMapper extends BaseMapper<Classz> {

    /**
     * 关联查询
     * @return
     */
    @Select("select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1")
    List<ClasszAndStudent> selectClassAndStudents();


}

3、测试


/**
 * @Auther: www.itzhimei.com
 * @Description:
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class ClassStudentTest {

    @Autowired
    private ClasszMapper classzMapper;

    @Autowired
    private StudentMapper studentMapper;
    @Test
    public void testSelect() {
        List<ClasszAndStudent> classzs = classzMapper.selectClassAndStudents();
        classzs.forEach(System.out::println);
        //classzs.get(0).getStudents().forEach(System.out::println);
    }

}

4、输出:

---------------SQL打印输出---------------
==>  Preparing: select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1 
==> Parameters: 
<==    Columns: ID, NAME, STDID, CID, STDNAME
<==        Row: 1, 一年一班, 1, 1, 小明
<==        Row: 1, 一年一班, 2, 1, 小欧
<==      Total: 2


-------------------代码打印输出----------------------
ClasszAndStudent(id=1, name=一年一班, stdId=1, cid=1, stdName=小明)
ClasszAndStudent(id=1, name=一年一班, stdId=2, cid=1, stdName=小欧)

我上面说到的平铺式的,就是这种效果:

ClasszAndStudent(id=1, name=一年一班, stdId=1, cid=1, stdName=小明)

另一种就是级联方式的返回查询结果。

1、构造实体,用于保存数据

package com.itzhimei.mybatis.plus.model;

import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description: 学生entity
 */

@Data
public class Student {
    private Long id;
    private Long cid;
    private String name;

    @TableField(exist = false)
    private Classz classz;
}
package com.itzhimei.mybatis.plus.model;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description: 班级entity
 */

@Data
public class Classz {
    private Long id;
    private String name;
}

2、在StudentMapper中添加一个级联查询方法

package com.itzhimei.mybatis.plus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itzhimei.mybatis.plus.model.Classz;
import com.itzhimei.mybatis.plus.model.Student;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description:
 */
public interface StudentMapper extends BaseMapper<Student> {

    /**
     * 一堆一的级联查询
     * @return
     */
    @Results(id="id",value = {
            @Result(property = "id",column = "id"),
            @Result(property = "name",column = "name"),
            @Result(property = "cid",column = "cid"),
            @Result(property = "classz",column = "cid", one = @One(select = "com.itzhimei.mybatis.plus.mapper.ClasszMapper.selectById"))
    })
    @Select("select * from student ")
    List<Student> selectStudentsAndClass();
}

注意代码中的注解,其中这一行:

@Result(property = "classz",column = "cid", one = @One(select = "com.itzhimei.mybatis.plus.mapper.ClasszMapper.selectById"))

作用就是执行了ClasszMapper.selectById()方法,用主键查询对应的班级,将查询结果set到了Student实体类中的Classz classz属性中(请看上面Student类中的属性)。

3、测试

package com.itzhimei.mybatis.plus.test;

import com.itzhimei.mybatis.plus.mapper.ClasszMapper;
import com.itzhimei.mybatis.plus.mapper.StudentMapper;
import com.itzhimei.mybatis.plus.model.ClasszAndStudent;
import com.itzhimei.mybatis.plus.model.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description:
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class ClassStudentTest {

    @Autowired
    private ClasszMapper classzMapper;

    @Autowired
    private StudentMapper studentMapper;

    @Test
    public void testSelectCascade() {
        List<Student> students = studentMapper.selectStudentsAndClass();
        students.forEach(System.out::println);
    }
}

4、输出

---------------SQL打印输出---------------
==>  Preparing: select * from student 
==> Parameters: 
<==    Columns: ID, CID, NAME
<==        Row: 1, 1, 小明
====>  Preparing: SELECT id,name FROM classz WHERE id=? 
====> Parameters: 1(Long)
<====    Columns: ID, NAME
<====        Row: 1, 一年一班
<====      Total: 1
<==        Row: 2, 1, 小欧
<==      Total: 2

-------------------代码打印输出----------------------
Student(id=1, cid=1, name=小明, classz=Classz(id=1, name=一年一班))
Student(id=2, cid=1, name=小欧, classz=Classz(id=1, name=一年一班))

看代码的输出结果:

Student(id=1, cid=1, name=小明, classz=Classz(id=1, name=一年一班))

Student中包含的Classz也带有数据,是这种Student(Classz)包含一个实体的效果,这就实现了一个一对一级联查询效果。