MyBatis:association和collection标签 - 分步查询

MyBatis:association和collection标签 - 分步查询

mybatis这两个标签都可以实现单步查询和分步查询,单步查询很好理解,如下:

参考

deptDaoMapper.xml:部门对应员工(1对多的关系)

<resultMap type="com.hw.entity.Dept" id="deptinfo"><!-- 如果不用resultMap则不写 -->
      <result column="did" property="did" />
      <result column="dname" property="dname" />
      <!-- mybatis中 1方配置多方 -->
      <collection property="per" ofType="com.hw.entity.Person">
          <result column="pid" property="pid" />
          <result column="pname" property="pname" />
          <result column="psex" property="psex" />
          <result column="skilled" property="skilled" />
          <result column="degree" property="degree" />
          <result column="jobtime" property="jobtime" javaType="java.sql.Date" jdbcType="DATE" />
          <result column="resume" property="resume" />
          <result column="filepath" property="filepath" />
      </collection>
  </resultMap>

personDaoMapper.xml:员工对应部门(多对一的关系)

<resultMap type="com.hw.entity.Person" id="personinfo"><!-- 如果不用resultMap则不写 -->
      <result column="pid" property="pid" />
      <result column="pname" property="pname" />
      <result column="psex" property="psex" />
      <result column="skilled" property="skilled" />
      <result column="degree" property="degree" />
      <result column="jobtime" property="jobtime" javaType="java.sql.Date"
          jdbcType="DATE" />
      <result column="resume" property="resume" />
      <result column="filepath" property="filepath" />
      <!--多对一的关系, property: 指的是属性的值, javaType:指的是属性的类型 -->
      <association property="dept" javaType="com.hw.entity.Dept">
          <result column="did" property="did" />
          <result column="dname" property="dname" />
      </association>
  </resultMap>

这时需要在sql语句中通过left join进行关联查询,接着在mybatis中进行关联表对象的封装Left join 语句

分步查询则无需在sql上写left joininner join语句,只需在进行主表查询的同时,通过传入子表查询的参数,即主表字段和子表查询参数进行绑定,主表在查询时,会默认通过主表的某个字段在子表的查询语句中进行递归查询,并将子表的查询结果封装在主表对应实体类的集合对象中。

这里仅介绍分步查询的用法。

1、collection分步查询 (1对多)

参考

package com.dpf.trainingPlan.entity;

import com.dpf.base.PageBaseEntity;
import com.dpf.person.entity.PersonEntity;
import com.dpf.organizion.entity.OrganizationEntity;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor
@Data
public class TrainingPlan extends PageBaseEntity {

private String pname;  //计划名称
private String startTime;  //计划开始时间
private String endTime;  //计划结束时间
private Integer organizationId;  //负责部门
private Integer personnelId;  //负责人
private String prequire;  //计划要求

private List<TrainingPlanFile> trainingPlanFileList;  //培训计划附件
private PersonEntity personEntity;  //人员管理
private OrganizationEntity organizationEntity; //组织管理
}

对于trainingPlanFileList对象,可以通过collection标签进行封装

<mapper namespace="com.dpf.trainingPlan.dao.TrainingPlanDao">

<resultMap id="baseMap" type="com.dpf.trainingPlan.entity.TrainingPlan">
  <id column="ID" property="id"/>
  <result column="PNAME" property="pname"/>
  <result column="START_TIME" property="startTime"/>
  <result column="END_TIME" property="endTime"/>
  <result column="ORGANIZATION_ID" property="organizationId"/>
  <result column="PERSONNEL_ID" property="personnelId"/>
  <result column="PREQUIRE" property="prequire"/>
  <result column="CREATE_BY" property="createBy"/>
  <result column="CREATE_DATE" property="createDate"/>
  <result column="CREATE_NAME" property="createName"/>
  <result column="UPDATE_BY" property="updateBy"/>
  <result column="UPDATE_DATE" property="updateDate"/>
  <result column="UPDATE_NAME" property="updateName"/>

		<association property="personEntity" select="com.dpf.person.dao.PersonDao.findPersonInfo"
               column="{id=PERSONNEL_ID}"/>

  <association property="organizationEntity" select="com.dpf.organizion.dao.OrganizationDao.findInforganization"
               column="{id=ORGANIZATION_ID}"/>

  <collection property="trainingPlanFileList" select="com.dpf.trainingPlan.dao.TrainingPlanFileDao.findTrainingPlanFile"
              column="{parentId=ID}">
  </collection>
</resultMap>
</mapper>

其中parentIdfindTrainingPlanFile的属性值,在调用findTrainingPlanFile之前,需要先将parentId封装到TrainingPlanFile对象中,如果parentId不是关联对象的属性值,会提示There is no getter or setter for PARENT_ID

ID是当前表中的ID字段,表示在子查询时,用当前表的ID字段,自动去关联表中进行查询和trainingPlanFileList对象封装

<select id="findTrainingPlanFile" parameterType="com.dpf.trainingPlan.entity.TrainingPlanFile" resultMap="baseMap">
  select *
  from training_plan_file
  where PARENT_ID = #{parentId} AND DEL_STATUS= '0'
</select>

这里还要注意的是:对于<collection>标签的select属性,既可以使用返回值为单个关联对象的查询方法(如上),也可以使用返回值为关联对象集合的查询方法(如下):

<select id="findList" parameterType="com.dpf.trainingPlan.entity.TrainingPlanFile" resultMap="baseMap">
       select *
       from training_plan_file
       where DEL_STATUS= '0'
       <if test="parentId != null ">
           AND PARENT_ID  = #{parentId}
       </if>
       <if test="fileUrl != null and fileUrl != '' ">
           AND FILE_URL = #{fileUrl}
       </if>
       <if test="fileName != null and fileName != '' ">
           AND FILE_NAME = #{fileName}
       </if>
   </select>

查询到结果都如下所示:
在这里插入图片描述

2、associaton分步查询(多对1,一对一)

参考

public class Employee {
	
	private Integer id;
	private String lastName;
	private String email;
	private String gender;
	private Department dept;
// 省略setter、getter、toString方法
}

public class Department {
	
	private Integer id;
	private String departmentName;
	private List<Employee> emps;
}

EmployeeMapper.xml

<!-- 使用association进行分步查询:
		1、先按照员工id查询员工信息
		2、根据查询员工信息中的d_id值去部门表查出部门信息
		3、部门设置到员工中;
	 -->
	 
	 <!--  id  last_name  email   gender    d_id   -->
	 <resultMap type="com.mybatis.bean.Employee" id="MyEmpByStep">
	 	<id column="id" property="id"/>
	 	<result column="last_name" property="lastName"/>
	 	<result column="email" property="email"/>
	 	<result column="gender" property="gender"/>
	 	<!-- association定义关联对象的封装规则
	 		select:表明当前属性是调用select指定的方法查出的结果
	 		column:指定将哪一列的值传给这个方法
	 		流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
	 	 -->
		<association property="dept" 
	 		select="com.mybatis.dao.DepartmentMapper.getDeptById"
	 		column="d_id">   
		</association>
	 </resultMap>

	 <!--  public Employee getEmpByIdStep(Integer id);-->
	 <select id="getEmpByIdStep" resultMap="MyEmpByStep">
	 	select * from tbl_employee where id=#{id}
	 </select>
	

其中部门表字段d_id的作用是与员工关联表的id字段进行绑定,填入到占位符#{id}进行查询

3、小总结

  • mybatis在resultmap手动映射中(假设resultMap的id为baseMap),通过collection标签(在sql上join关联查询/分步查询)可以实现在对主表查询的同时,完成对子表的查询,并将子表的查询结果封装在主表的对象集合中(前提是在查询的方法中,返回类型,即resultMap类型为baseMap,它才会自动封装)。
  • 这样的关联查询往往和业务相关,如果前端页面只需要展示主表信息即可,则无需配置这个collection标签。
  • 这两个标签的作用都是自动将该实体类A对应的数据表的关联表的查询结果,封装到该关联表对应的实体类对象B中,实体类A通过对象B这个property, 扩充了它向外界展示的信息
  • 对于关联查询,有两种实现方式:一种是在mybatis数据库层面进行关联查询(inner join或者分步查询),在主表中查询完一条数据之后,关联查询相关数据;
    另一种是在service层面进行关联查询,这时对主表的所有查询结果进行依次遍历,接着再根据每个对象某个属性值去查询相关关联数据,并封装到该对象的关联对象中。
    对于第一种方法,对数据库的负载要求较高,而对于第二种方法,对服务器的负载要求较高
  • 如果在关联查询时,主表要查询的关联表的实体类不在自己开发的模块中,并且该关联类没有提供接口(无法生成代理类),使得我们无法在主表的实体类上创建该关联表对象,因此在mybatis层上关联查询会存在问题。因此需要通过调用关联表对象的service层接口实现查询,在自己的service层上实现关联查询。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值