我们本节演示表关联查询和两个表一对一的级联查询。
两个表关联后,返回的结果我们有两种返回结果集的方式,一种是平铺方式,也就是两个表的字段都放到一个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)包含一个实体的效果,这就实现了一个一对一级联查询效果。