三层多对多关系查询方法

  • Post author:
  • Post category:其他




场景描述

假设模仿健康体检的项目场景,体检的各个项目称为检查项,多个检查项能够组成一个体检组,例如普通检查组包括了身高、体重、血压等等的体检项。同时多个检查组能够组成一个检查套餐。

三者之间的关系是多对多的关系,同一个检查项可以在不同的检查组,同一个检查组可以在不同的检查套餐。



实现效果

通过给出一个检查套餐的id值,能够查出其包含的所有检查组,同时根据这些检查组能够查出每个检查组里面的检查项的详细信息,就是对两重的多对多关系的查询。



前期准备

根据场景的描述,先准备体检项、体检组、体检套餐的POJO类,对应的持久层的配置文件。这里采用的是MyBatis作为持久层框架,通过编写Dao的xml配置文件来实现对数据库的操作。

列出了检查项、检查组和套餐的数据表表名和类的名称。

检查项 检查组 套餐
数据库表名 tab_inspectitem tab-inspectgroup tab_setmeal
POJO类 InspectItem InspectGroup Setmeal
*Dao.xml InspectItemDao.xml InspectGroupDao.xml SetmealDao.xml

检查项、检查组和套餐的中间表的名称。

tab_inspectgroup_inspectItem #检查项与检查组关联的中间表

tab_setmeal_inspectgroup #检查项与检查组关联的中间表

POJO的InspectItem 类

import java.io.Serializable;

/**
 * 检查项
 */
public class InspectItem implements Serializable {
    private Integer id;//主键
    private String code;//项目编码
    private String name;//项目名称
    private String sex;//适用性别
    private String age;//适用年龄(范围),例如:20-50

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

InspectGroup类

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

/**
 * 检查组
 */
public class InspectGroup implements Serializable {
    private Integer id;//主键
    private String code;//编码
    private String name;//名称
    private String sex;//适用性别
    private List<InspectItem > inspectItems;//一个检查组合包含多个检查项

    public List<InspectItem > inspectItems() {
        return inspectItems;
    }

    public void setInspectItems(List<InspectItem> inspectItems) {
        this.inspectItems= inspectItems;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

   
    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

Setmeal类

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

/**
 * 体检套餐
 */
public class Setmeal implements Serializable {
    private Integer id;
    private String name;
    private String code;
    private String sex;//套餐适用性别:0不限 1男 2女
    private String age;//套餐适用年龄
    private List<InspectGroup> inspectGroups;//体检套餐对应的检查组,多对多关系

    public List<InspectGroup> getInspectGroups() {
        return inspectGroups;
    }
    public void setInspectGroups(List<InspectGroup> inspectGroups) {
        this.inspectGroups = inspectGroups;
    }
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}



实现过程

根据要达到的要求,通过service层调用dao层的方法,可以根据Setmeal的id来查找套餐的详细内容,Setmeal的属性包含了一个装有InspectGroup类的list集合,而且InspectGroup类中也包含了一个装有InspectItem类的list集合。

这一连串的查找都是通过传入一个Setmeal的id来触发的。

假设Setmeal的service层调用了SetmealDao的

findById()

方法。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.gochen.dao.SetmealDao">
    
    <resultMap id="BaseResultMap" type="com.gochen.pojo.Setmeal">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="sex" property="sex"/>
        <result column="age" property="age"/>
    </resultMap>
    <!-- 
			collection定义关联集合类型的属性的封装规则 
			ofType:指定集合里面元素的类型
		-->
    <resultMap id="findByIdResultMap" type="com.gochen.pojo.Setmeal" extends="BaseResultMap">
        <collection property="inspectGroups" javaType="ArrayList" ofType="com.gochen.pojo.InspectGroup"
                    column="id"
                    select="com.gochen.dao.InspectGroupDao.findInspectGroupById"></collection>
    </resultMap>

    <select id="findById" parameterType="int" resultMap="findByIdResultMap">
        select * from t_setmeal where id = #{id}
    </select>
</mapper>

因为存在着多对多的关系,同时也要查出所有的数据,所以不能单单用resultType来决定返回值的类型,所以要定义自己的返回值的结果集,即使用了resultMap。

将resultMap映射为

findByIdResultMap

,在

findByIdResultMap

中通过

extends属性

继承了Setmeal的基础

BaseResultMap

来查找Setmeal其他属性的值。



findByIdResultMap

中的属性

column="id"

,将list集合中的

InspectGroup

的id传到属性select中描述的

InspectGroupDao.findInspectGroupById

来查找InspectGroup的详细内容。

因为

findInspectGroupById()

方法来自InspectGroupDao,所以看InspectGroupDao.xml的配置信息:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.gochen.dao.InspectGroupDao">

    <resultMap id="BaseResultMap" type="com.gochen.pojo.InspectGroup">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="code" property="code"/>
        <result column="sex" property="sex"/>
    </resultMap>
    <resultMap id="findByIdResultMap" type="com.gochen.pojo.InspectGroup">
        <collection property="inspectItems" javaType="ArrayList" ofType="com.gochen.pojo.InspectItem"
                    column="id"
                    select="com.gochen.dao.InspectItemDao.findInspectItemById"></collection>
    </resultMap>


    <select id="findInspectGroupById" parameterType="int" resultMap="findByIdResultMap">
        select * from t_inspectgroup where id in (select inspectgroup_id from t_setmeal_inspectgroup where setmeal_id = #{id})
    </select>
</mapper>

在InspectGroupDao.xml中的查找方法是SetmealDao.xml指定的方法,这时id就会传进去,也就是

检查组的id

,进而查找其装有InspectItem类的list集合里面的id,然后传到

InspectItemDao.findInspectItemById()

的方法中,其调用的流程和SetmealDao.xml调用的过程一样,这里就不赘述了。

最后就到InspectItemDao.xml配置信息了:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
        
<mapper namespace="com.gochen.dao.InspectItemDao">

    <select id="findInspectItemById" parameterType="int" resultType="com.gochen.pojo.InspectItem">
        select * from t_inspectitem where id in (select inspectitem_id from t_inspectgroup_inspectitem where inspectgroup_id = #{id})
    </select>

</mapper>

到这里,检查项已经是最小项了,所以在InspectItemDao.xml中只要实现

findInspectItemById()

方法就行了。



版权声明:本文为haroroc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。