常见表关系
秘诀:从一头出发,所在位置不同,得到的结果也不同
1.一对一 例子:一个老公对应一个老婆,一个员工对应一个部门
2.一对多 例子:一个部门对应多个原
3.多对多 例子:一个学生对应多个老师,一个老师对应多个学生
一个角色对应多个权限,一个权限对应多个角色 多对多其实就是双向的一对多
4.多对一 实质:站在一头出发,所以就是一对一
Mybatis中映射规则:结果集中不允许出现重名字段
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Emp implements Serializable {
private Integer empId;
private String empName;
//关联关系 1: 一个员工对应一个部门
private Dept dept;
}
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
//一个部门对应多个员工
private List<Emp> emps;
}
需求:进行一对一查询,一个员工对应一个部门(看pojo,不要有疑问)
sql:select * from emp e,dept d where e.dept_id = d.dept_id //一对一关联查询
难点:如何完成一对一的封装
固定用法:association:将结果集封装为单独的对象dept
2.property 需要封装的属性名称
3.javaType 固定用法: 属性的类型
下面是完整的代码:findAll()不必多说,就是查的sql中的数据,可以看出dept是包含deptId和deptName的,需要将dept类的两个属性封装为dept对象(实例)中
<select id = "findAll" resultMap = "empRM">
select e.emp_id,e.emp_name,d.dept_id,d.dept_name from emp e,dept d
where e.dept_id = d.dept_id
</select>
<resultMap id= "empRM" type = "Emp">
//映射主键,xml中不可以使用//注释,这里图个快捷
<id property="empId" column="emp_id'></id>
//映射其他字段
<result property="empName" column="emp_name'></result>
<association property ="dept" javaType = "Dept">
//完成dept对象的封装
<id property="id" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
需求:进行一对多查询,一个部门对应多个员工(这里看pojo就知道要封装,不要疑问)
sql:select d.dept_id,d.dept_name,e.emp_id,e.emp_name from dept d,emp e
where d.dept_id = e.emp_id
难点:如何将emp中查到的数据数据封装到集合list<Emp>集合中
固定用法:collection标签封装集合,在这里表示将同一个部门下得员工封装到一个集合中
property表示要封装成的集合名称
ofType表示元素类型
<select id="findAll" resultMap="deptRM">
select d.dept_id,d.dept_name,e.emp_id,e.emp_name
from dept d,emp e
where d.dept_id=e.emp_id
</select>
<resultMap id="deptRM" type="Dept">
<id property="deptId" column="dept_id'></id>
<result propery="deptName" column="dept_name"></result>
<collection property="emps" ofType="Emp">
<id property="empId" column="emp_id"></id>
<result property="empName" column="emp_name"></result>
</collection>
</resultMap>
注意:表有主次之分的,分的主次可以简单很多,Mybatis的封装一般都是一级封装
Mybatis的子查询
矛盾点:1.如果想简化sql,则映射文件肯定复杂 2。如果想简化映射文件,则sql语句复杂
需求:使用子查询来完成封装
子查询本质特点:将多表关联查询,转化为多个单表查询
思考;这个既然要使用子查询的,但是返回值不仅仅是dept一张表的数据(这里和上面一样实现一对多,只是换种方法),所以常规的sql:
select dept_id,dept_name from emp where dept_id in (select dept_id from emp)肯定不可以
最终目的是将emp查询的数据封装List<Emp> emps集合对象中
代码如下:
<select id="selectChildren" resultMap="deptRM">
select * from dept
//这里可以写成select dept_id,dept_name from dept, 由于表中没有字段emps,
写在这里报错,就这样写结果也是可以封装的,自己已经验证过,所以遇到当字段只是表中
的一部分但是业务需要封装时,这时就需要将指定的字段写在这里,而不能只写个*就可以
</select>
<resultMap id="deptRM" type="Dept">
//映射主键
<id property="deptId" column="dept_id"></id>
//映射其他字段
<result property="deptName" column="dept_name"></result>
//数据集合封装
<collection property="emps" ofType="Emp" select="findEmp" column="dept_id"></collection>
</resultMap>
//二次查询,将column="dept_id"字段的值作为参数,传递给子查询
<select id="findEmp" resultMap="empRM">
select * from where dept_id=#{dept_id}
//这里的#{dept_id}就是上面映射字段的dept_id,通俗点的意思就是
将dept_id中查出来dept_id给到当前表中使用。这里的*可以替换为具体的
字段emp_id,emp_name
</select>
<resultMap id="empRM" type="Emp">
//映射主键
<id property="empId" column="emp_id"></id>
//映射其他字段
<result property="empName" column="emp_name">
</resultMap>
同理,一对一的封装,一个员工对应一个部门的封装代码为:
<select id="findAllSelect" resultMap="empRM2">
select * from emp
</select>
<!--进行数据封装-->
<resultMap id="empRM2" type="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<association property="dept" javaType="Dept" select="selectDept" column="dept_id"></association>
</resultMap>
<select id="selectDept" resultMap="deptRM">
select * from dept where dept_id= #{dept_id}
</select>
<resultMap id="deptRM" type="Dept">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</resultMap>