Java -- MyBatis学习笔记13、联合查询(二)

1、多对一关联

就是某一张表的多条数据、对应另一张表的一条数据,比如多个学生对应一个班级。

1.1、提出需求

以学生表和班级表为例、查询学生信息,并查询对应的班级,关系为多对一。

  • 表字段以及对应关系

1.2、创建实体类

学生表存放班级id,在实体类中取而代之的就是班级实体类类型,一个班级下有多名学生,所以、在班级实体类中必须有一个集合类型属性,集合里边类型为学生类型、将查询到的学生学生映射到该集合当中。

  • 学生实体类
public class Student {
    private int id;
    private String stu_name;
    private int stu_age;
    private String address;
    private Classes classes;
    //getter and setter...
}
  • 班级实体类
public class Classes {
    private int id;
    private String class_name;
    //一个班级对应多名学生,使用集合、存放学生信息
    private List<Student> students;
    //getter and setter...
}
  • 定义Dao层接口
public interface StudentDao {
    List<Student> selectStudents();
}
  • mapper映射文件
<mapper namespace="com.rg.dao.StudentDao">
    <!--
        方式一:直接联合查询、然后给实体类中每个属性赋值
    -->
    <select id="selectStudents" resultMap="student_class_map">
        select s.*, sc.id, sc.class_name
        from student s
                 inner join student_class sc on s.s_id = sc.id
    </select>
    <resultMap id="student_class_map" type="com.rg.bean.Student">
        <id property="id" column="id"/>
        <result property="stu_name" column="stu_name"/>
        <result property="stu_age" column="stu_age"/>
        <result property="address" column="address"/>
        <!--
            通过association标签、将关联查询到的班级信息,存放到classes属性当中
        -->
        <association property="classes" column="s_id" javaType="com.rg.bean.Classes">
            <id property="id" column="id"/>
            <result property="class_name" column="class_name"/>
        </association>
    </resultMap>

    <!--
        方式二:通过执行另外一个SQL映射语句来返回预期的复杂类型
    -->
    <select id="selectStudents" resultMap="student_map">
        select id, stu_name, stu_age, address, s_id
        from student
    </select>
    <resultMap id="student_map" type="com.rg.bean.Student">
        <id property="id" column="id"/>
        <result property="stu_name" column="stu_name"/>
        <result property="stu_age" column="stu_age"/>
        <result property="address" column="address"/>
        <!--关联另一条sql语句,将s_id传入、将查询到的结果映射到classes属性当中-->
        <association property="classes" select="selectClasses" column="s_id"/>
    </resultMap>
    <!--根据学生表的班级id,查询对应的班级-->
    <select id="selectClasses" resultType="com.rg.bean.Classes">
        select id,class_name from student_class where id = #{id}
    </select>
</mapper>
  • 测试
@Test
public void test02() {
    List<Student> students = studentDao.selectStudents();
    for (Student student : students) {
        System.out.println(student);
    }
}
  • 查询结果
Student{id=14, stu_name='小王', stu_age=15, address='河南', classes=Classes{id=1, class_name='软件2021班', students=null}}
Student{id=15, stu_name='小李', stu_age=13, address='河南', classes=Classes{id=2, class_name='软件2022班', students=null}}
Student{id=16, stu_name='小赵', stu_age=14, address='上海', classes=Classes{id=1, class_name='软件2021班', students=null}}

其实多对一就相当于多个一对一,每次查询到一条学生信息,就根据学生信息中的班级id关联到班级表、查询到对应的班级信息。

2、一对多关联

在mybatis中进行一对多关联要使用到一个集合标签,因为每次查询到一条数据,就要关联到另一张表中的多条数据,也就是说、查询到一条班级信息,就要拿着这条数据的id,到学生表中查对应的学生信息,将查到的这些学生对象,逐条添加集合当中。

2.1、提出需求

根据班级id,查询班级信息并查到学生表中对应的所有学生信息。

  • mapper映射文件
<mapper namespace="com.rg.dao.StudentDao">
    <!--
        方式一:直接两表联合查询、将结果通过resultMap映射到实体类
    -->
    <select id="selectClasses" resultMap="classes_student_map">
        select c.*, s.stu_name
        from student_class c
                 inner join student s on c.id = s.s_id
        where c.id = #{id}
    </select>
    <resultMap id="classes_student_map" type="com.rg.bean.Classes">
        <id property="id" column="id"/>
        <result property="class_name" column="class_name"/>
        <!--
               students为集合类型、所以通过collection标签进行遍历映射
               collection标签是集合标签,它与association关联标签几乎是一样的
        -->
        <collection property="students" ofType="com.rg.bean.Student">
            <result property="stu_name" column="stu_name"/>
        </collection>
        <!--
            在MyBatis框架中,JavaType和ofType都是用来指定对象类型的。
            JavaType和ofType的区别在于:JavaType用来指定POJO中属性的类型。
            ofType指定的是映射到List集合中POJO的类型。
        -->
    </resultMap>

    <!--
        方式二:嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
    -->
    <select id="selectClasses" resultMap="classes_student_map">
        select id,class_name from student_class where id = #{id}
    </select>
    <resultMap id="classes_student_map" type="com.rg.bean.Classes">
        <id property="id" column="id"/>
        <result property="class_name" column="class_name"/>
        <!--
            通过select属性、指定要执行的sql语句
        -->
        <collection property="students" column="id" select="selectStudents" ofType="com.rg.bean.Student"/>
    </resultMap>
    <select id="selectStudents" resultType="com.rg.bean.Student">
        select stu_name from student where s_id = #{id}
    </select>

    <!--
        方式三:直接两表联合查询、将结果通过resultMap映射到实体类,使用resultMap嵌套
    -->
    <select id="selectClasses" resultMap="classes_student_map">
        select c.*, s.stu_name,s.id as sid
        from student_class c
                 inner join student s on c.id = s.s_id
        where c.id = #{id}
    </select>
    <resultMap id="classes_student_map" type="com.rg.bean.Classes">
        <id property="id" column="id"/>
        <result property="class_name" column="class_name"/>
        <!--
            再通过resultMap属性、在外边定义resultMap标签、进行映射赋值
        -->
        <collection property="students" resultMap="classes_map"/>
    </resultMap>
    <!--
        这里一定要注意,如果两张表的字段重名的话一定要定义别名。
        如student_classes表的主键是id,student表中的主键也是id,那么
        在当前resultMap中给id赋值,有可能会将班级的id值赋给了学生的id
        所以在两表联合查询时候要根据需要定义别名,如下:
        将student表的id定义别名为sid,将sid和Student实体类中的id赋值
        如果不这样,赋的值就有可能是student_class表的id值
    -->
    <resultMap id="classes_map" type="com.rg.bean.Student">
        <!--这个sid是student表的id值-->
        <id property="id" column="sid"/>
        <result property="stu_name" column="stu_name"/>
    </resultMap>
</mapper>
  • 结果
软件2021班
该班级有如下学生:
Student{id=14, stu_name='小王', stu_age=0, address='null', classes=null}
Student{id=16, stu_name='小赵', stu_age=0, address='null', classes=null}
原文地址:https://www.cnblogs.com/dcy521/p/15092387.html