SQL查询映射到对象中的对象(自定义resultMap)
需求背景
在开发工作中,我们有时候会遇到这样一个场景:需要从多个数据表中取出需要的数据,返回给接口调用者。这时候就有两个选择,1是用单表查询分别从多个表中取出数据,在代码里进行拼接,最后合起来返回,2是连表查询,用一个查询就查出所需要的数据,并映射到实体类上。这里主要讲讲第二种方式,重点是如何将查询结果映射到实体类里的实体类。
比如我现在要通过用户id查询用户基本信息,包括用户的座驾的基本信息,但是数据结构一般只会设计为用户表,汽车表,用户表中用汽车表主键与汽车表关联。所以,我们需要查询两个实体类,才能得到我们想要的数据。其实也可以通过连表查询来查出我们想要的数据。通过建一个既有用户信息又有汽车信息的实体类,来进行sql查询结果的映射。
实体类UserInfo:
@Data
@Table(name = "TABLE_USER")
public class UserInfo {
private Integer id;
private String userName;
private Integer sex;
private Integer age;
private Integer carId;
}
实体类CarInfo:
@Data
@Table(name = "TABLE_CAR")
public class CarInfo {
private String color;
private String brand;
private Integer price;
}
要返回的实体类UserCarVO:
@Data
public class UserCarVO {
private Integer id;
private String userName;
private Integer sex;
private Integer age;
private CarInfo myCar;
}
连表查询
<select id="selectByUserId" resultType="com.minhai.boot.entity.UserCarVO">
SELECT U.ID id,
U.USER_NAME userName,
U.SEX sex,
U.AGE age,
C.COLOR color,
C.BRAND brand,
C.PRICE price
FROM TABLE_USER U
JOIN TABLE_CAR C
ON U.CAR_ID = C.ID
AND U.ID = #{userId}
</select>
程序运行结果:
理论上,通过连表查询就能查出我们需要的结果,但是实际上,映射的结果是这样的:
这里的汽车信息是null,为什么会发生这种情况呢?原因是mybatis只能映射一层实体类,这里的myCar 是在UserCarVO里的实体类,它无法注入到第二层去。这个时候,就需要我们自定义resultMap了。
自定义resultMap
<resultMap id="UserCarVOMap" type="com.minhai.boot.entity.UserCarVO">
<id column="ID" property="id"/>
<result column="USER_NAME" property="userName"/>
<result column="SEX" property="sex"/>
<result column="AGE" property="age"/>
<association property="myCar" javaType="com.minhai.boot.entity.CarInfo">
<result column="COLOR" property="color"/>
<result column="BRAND" property="brand"/>
<result column="PRICE" property="price"/>
</association>
</resultMap>
这里自定义一个resultMap,用来映射UserCarVO。用 association 标签来关联实体类CarInfo,这样,我们连表查询的结果就能映射到 UserCarVO 里的 CarInfo 实体类了。
程序运行结果:
这里的myCar就能够通过查询结果映射上去了。
总结
在开发过程中,我们需要评估两种方式的效率。第一种方法的优点是:SQL简单,单个查询效率较高。但是多次查询会花费很多时间在建立连接上面,影响 IO 性能,并且需要在代码里自行拼接返回数据。第二种方式就只用一个SQL,但是SQL复杂,执行速度可能较慢,但是能够直接注入到实体类,不需要在代码里进行返回数据的拼接。两种方式各有利弊,可按照实际情况选择。