ResultMap中鉴别器说明
在查询结果中,有时候一个数据库的查询结果会返回多个不同的结果集(总结上是有一定联系的)。discriminator成为鉴别器,类似于java语句中的switch语句,正是用于处理这种情况。并且,discriminator还能够处理包含继承层次的结果映射。
ResultMap中鉴别器使用实例
之前的一篇文章中,根据MyBatis官方给出的代码示例,尝试构建数据表和类结构完成了示例中较为复杂的一个ResultMap的使用实例,具体见: MyBatis中ResultMap使用实例解析。这里同样根据如下的MyBatis官方文档给出的示例,来说明resultMap中discriminator的使用。MyBatis官方文档中在对dircriminator进行说明的时候,使用了如下的示例:
根据上述的配置代码,在对查询结果进行映射的过程中,会根据vehicle_type查询列的结果,使用case元素进行对应。例如,当vehicle_type=1时,则将结果映射为carResult(这里应该是Car类的定义的别名)对象,而Car为Vehicle的子类,具有额外的一个doorCount属性,因此此时查询结果集映射后得到的对象实例应该是Car类的对象。不仅包含Vehicle中的基础属性,还包含额外的doorCount属性。同样的,当vehicle_type分别等于2,3,4时,则会分别映射为Vehicle子类的Truck,Van和Suv类的对象。而当vehicle_type不对应于case中定义的各个值时,将会映射为外层的Vehcile父类对象。这就是discriminator(鉴别器)的作用。
创建相应的父类和子类结构和表结构
根据上述的示例分析,现在实现该实例。首先将其中的属性进行了改变,然后定义了父类Vehicle和相应的子类Car,Truck和Suv如下:
@Data
public class Vehicle {
private Integer id; // id
private String brand;
private String color;
private Date productDate;
private Integer vehicleType;
}
@Data
public class Car extends Vehicle {
private Integer doorCount;
}
@Data
public class Suv extends Vehicle {
private Boolean allWheelDriver;
}
@Data
public class Truck extends Vehicle {
private Integer boxSize;
private String capacity;
}
创建对应的tb_vehicle表结构并插入相应的数据:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_vehicle
-- ----------------------------
DROP TABLE IF EXISTS `tb_vehicle`;
CREATE TABLE `tb_vehicle` (
`id` int(11) NOT NULL,
`brand` varchar(255) DEFAULT NULL,
`color` varchar(255) DEFAULT NULL,
`product_date` datetime DEFAULT NULL,
`vehicle_type` int(255) DEFAULT NULL,
`door_count` int(255) DEFAULT NULL,
`all_wheel_driver` tinyint(255) DEFAULT NULL,
`box_size` int(11) DEFAULT NULL,
`capacity` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of tb_vehicle
-- ----------------------------
BEGIN;
INSERT INTO `tb_vehicle` VALUES (1, 'BMW', 'red', '2020-02-02 00:00:00', 1, 4, 0, 2, '50');
INSERT INTO `tb_vehicle` VALUES (2, 'Maserati', 'blue', '2019-01-01 00:00:00', 2, 4, 0, 2, '80');
INSERT INTO `tb_vehicle` VALUES (3, 'Ford', 'black', '2020-02-12 00:00:00', 3, 2, 1, 4, '200');
INSERT INTO `tb_vehicle` VALUES (4, 'CAT', 'yellow', '2019-04-01 00:00:00', 0, 2, 1, 0, '1000');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
插入的四条数据的vehicle_type分别为1,2,3,0,分别对应Car,Suv,Truck和Vehicle四个类的查询结果映射。
构造MyBatis结果映射
根据上述的表和类,构造SQL的查询语句和影响的结果映射ResultMap,vehicleMapper.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zyt.springbootlearning.dao.VehicleMapper">
<resultMap id="vehicleMap" type="cn.zyt.springbootlearning.domain.mybatis.discriminator.Vehicle">
<id property="id" column="id"/>
<result property="brand" column="brand"/>
<result property="color" column="color"/>
<result property="productDate" column="product_date"/>
<result property="vehicleType" column="vehicle_type"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultType="cn.zyt.springbootlearning.domain.mybatis.discriminator.Car">
<result property="doorCount" column="door_count"/>
</case>
<case value="2" resultType="cn.zyt.springbootlearning.domain.mybatis.discriminator.Suv">
<result property="allWheelDriver" column="all_wheel_driver"/>
</case>
<case value="3" resultType="cn.zyt.springbootlearning.domain.mybatis.discriminator.Truck">
<result property="boxSize" column="box_size"/>
<result property="capacity" column="capacity"/>
</case>
</discriminator>
</resultMap>
</mapper>
这里可以看到使用了discriminator来进行结果的不同映射,使用vehicle_type字段来区分映射的关系。并针对不同的映射类型,设置相应包含的映射字段。下面编写VehicleMapper.java映射接口文件:
@Repository
public interface VehicleMapper {
@Select("select * from tb_vehicle where id=#{id}")
@ResultMap("vehicleMap")
Vehicle getVehicle(Integer id);
@Select("select * from tb_vehicle")
@ResultMap("vehicleMap")
List<Vehicle> getVehicleList();
}
然后编写简单的Controller来直接调用Mapper对象的getVehicleList方法获取查询结果,返回JSON数据结构:
从上述结果可以看到,同一个表中查询出来的4条数据,分别被映射为四个不同的类对象(从上述四条结果中包含不同的字段可以看出),分别对应Car,Suv,Truck和Vehicle,前三者在分别包含Vehicle中基本属性的同时,各自具有分别不同的属性值。