使用 <resultMap>结果映射的方式存储多表查询结果。是对MyBatis入门七:多表关联查询一:获取多表关联查询结果;(查询结果包括多张表的字段,使用Map去承载存储查询结果)的改进。
目录
(1)因为关联查询结果的字段包括t_goods表中的字段和t_category表中的字段,所以先创建t_category表对应的实体类:(这是一种非常好的编程风格和习惯)
(2)扩展一个java类:DTO类,让其可以保存多表关联查询的结果:
(3)然后,如何让mybatis把查询结果自动对应赋值给这个GoodsDTO类对象?就需要使用resultMap结果映射了
(4)测试&运行结果
(5)几点说明
在MyBatis入门七:多表关联查询一:获取多表关联查询结果;(查询结果包括多张表的字段,使用Map去承载存储查询结果)中提供了一种解决多表查询结果的方法,即使用Map(具体是使用LinkedHashMap这种数据结构)去承载存储多表查询的结果。但是也提到,这并不是一种最好的解决方案,在多人协作开发的时候,配合的体验并不好。
那么,如果不使用Map,如何使用对象的方式来保存多表关联查询的结果?
因为多表关联查询的时候,查询结果肯定包含多张表的字段,为了继续使用对象的方式(这种方式,在多人协作开发的时候,配合体验很好)来保存多表关联查询的结果,这儿的基本思路是先定义一个***DTO类,然后再在goods.xml中书写select标签和resultMap映射,最后调用就可以了。
沿用上篇博客的案例:查询t_goods表和t_category表:
(1)因为关联查询结果的字段包括t_goods表中的字段和t_category表中的字段,所以先创建t_category表对应的实体类:(这是一种非常好的编程风格和习惯)
Category实体类内容:(代码很长,快速浏览即可,没什么意思~~)
package com.imooc.mybatis.entity;
/**
*商品类型表实体类,与t_category表对应;
*/
public class Category {
private Integer categoryId; //类别ID
private String categoryName; //类名名称
private Integer parentId; //该类别的父类别ID
private Integer categoryLevel; //类别的等级(是一级类别还是二级类别,,,或者说该类别是否有父类别)
private Integer categoryOrder; //前端显示的顺序,数字小的在查询结果中优先排序显示
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public Integer getCategoryLevel() {
return categoryLevel;
}
public void setCategoryLevel(Integer categoryLevel) {
this.categoryLevel = categoryLevel;
}
public Integer getCategoryOrder() {
return categoryOrder;
}
public void setCategoryOrder(Integer categoryOrder) {
this.categoryOrder = categoryOrder;
}
}
(2)扩展一个java类:DTO类,让其可以保存多表关联查询的结果:
GoodsDTO类:这个扩展的javaBean就包含了Goods这个实体类和Category实体类,自然可以用GoodsDTO类对象去承载和存储【既包含t_goods表中的字段又包含t_category表中的字段的查询结果了】;(能懂,OK)
package com.imooc.mybatis.dto;
import com.imooc.mybatis.entity.Category;
import com.imooc.mybatis.entity.Goods;
public class GoodsDTO {
private Goods goods = new Goods();
private Category category = new Category();
private String test;
public Goods getGoods() {
return goods;
}
public void setGoods(Goods goods) {
this.goods = goods;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
(3)然后,如何让mybatis把查询结果自动对应赋值给这个GoodsDTO类对象?就需要使用resultMap结果映射了
注意,这儿不再使用resultType了;而是使用的resultMap;
(4)测试&运行结果
package com.imooc.mybatis;
import com.imooc.mybatis.dto.GoodsDTO;
import com.imooc.mybatis.entity.Goods;
import com.imooc.mybatis.utils.MyBatisUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* JUnit单元测试类
*/
public class MyBatisTestor {
@Test
public void testSelectGoodsDTO() throws Exception {
SqlSession session = null;
try {
session = MyBatisUtils.openSession();
List<GoodsDTO> list = session.selectList("goods.selectGoodsDTO");
for (GoodsDTO goodsDTO : list) {
System.out.println(goodsDTO.getGoods().getTitle()+":"+goodsDTO.getCategory().getCategoryName());
}
} catch (Exception e) {
throw e;
}finally {
MyBatisUtils.closeSession(session);
}
}
}
运行结果:
(5)几点说明
(1) 为了解决上面的问题,其并没有修改原始的Goods实体类。这是一种应该遵循的习惯和策略,即一个实体类就是和一个数据表对应(类名和表名对应,属性名和字段名对应)。
(2) 其实上面这样做也是可以的:因为本次关联查询的结果中有t_category表的category_name字段,我们不用编写Category实体类:而是:
然后,在resultMap结果映射中设置一下即可。
运行结果:
这种处理策略可以选中的场景:查询结果中只有一两个t_category表的字段。(如果查询结果中有很多t_category表的字段,还是新建一个Category实体类比较好。。。能懂吧,OK)
但是,这这种处理策略更像是一种为了应对当前业务,而“ 临时的 解决方案”,正规的解决办法还是像上面那样,创建t_category表的实体类Category类,然后再将Category对象设置成GoodsDTO类的一个属性。
(3) 发现,<resultMap>中不写id标签也是可以运行的
(4) 自然,在<resultMap>中,查询结果中的同一个字段的值,可以赋值给多个属性
(5) 【<resultMap>的方式存储查询结果】和【Map存储查询结果】的比较
在实际开发时,<resultMap>的好处是可以把多表关联查询的复杂结果映射成对应的一个实体类对象(DTO对象)进行保存。在获取查询结果的时候,可以非常清晰的获取到对应的属性,协作开发体验很好,不再像Map一样一脸懵逼容易出错。
但是,<resultMap>需要额外的书写大量的映射规则,略略麻烦。究竟使用Map来保存查询结果,还是使用<resultMap>的方式保存结果根据需要选择。如果是自己写的,或者小的项目就可以使用Map来保存负责结果;但是如果多人协作的时候,建议使用<resultMap>的方式来保存查询结果。