问题描述
在使用mybaits-plus的时候定义的Mapper接口实现了BaseMapper,没有编写Mapper对应的xml,大部分查询使用框架的接口进行查询基本属性返回都是正常,复杂对象在sql中会进行查询,但是返回对象中却未包含相关属性。
问题原因
没有开启自动映射
实体类在使用@TableName
注解修饰时,在具有复杂对象的实体中没有开启autoResultMap
属性映射,这样在本身没有编写Mapper.xml的情况下会导致框架只会生成基础属性的映射,复杂对象不会处理,即使在复杂字段上标注了typeHandler = JacksonTypeHandler.class
也无济于事。
使用@Select
注解自定义SQL
实体类开启了autoResultMap
属性映射,但是在Mapper接口中使用@Select
注解编写来进行查询。使用框架提供的查询方法复杂属性能正常返回,但是使用自定义查询复杂属性返回为空。
解决方案
未开启自动映射-开启自动映射
因为autoResultMap
默认是false的,如果实体对象中没有复杂属性,则不开也无所谓,mybatis-plus框架会将基础属性自动进行映射;但是如果实体使用了json,list等复杂属性,则需要显示开启自动映射,并且在@TableField
中表明使用的handler
类型,这样框架才会在查询出值之后知道怎么利用哪个handler
来进行值的转换。
解决效果
库中的值
未开启自动映射查询结果
涉及的类
@TableName(value = "user_table")
@Data
public class UserEntity {
private String name;
private Integer age;
@TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)
private List<String> tableDesc;
}
@Mapper
public interface UserEntityMapper extends BaseMapper<UserEntity> {
}
//使用框架的查询
@RestController
@RequestMapping("/test")
public class TestController {
@Resource
UserEntityMapper userEntityMapper;
@GetMapping("/query")
public String getQuery(){
return JSONObject.toJSONString(userEntityMapper.selectList(null));
}
}
查询结果
[
{ "age": 4, "name": "123" },
{ "age": 1, "name": "33333" }
]
开启自动映射
涉及的类
@TableName(value = "user_table",autoResultMap = true)
@Data
public class UserEntity {
private String name;
private Integer age;
@TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)
private List<String> tableDesc;
}
查询结果
[
{ "age": 4, "name": "123", "tableDesc": [ "age", "123" ] },
{ "age": 1, "name": "33333", "tableDesc": [ "1123", "2131" ] }
]
使用@Select
自定义SQL-使用@ResultMap
指定映射
使用@ResultMap
的前提是开启了自动映射,这样框架生成的ResultMap
对象中会包含我们指定对象的handler
类,然后在@Select
方法上添加@ResultMap
注解,这样框架在执行自定义的SQL语句时就会知道使用哪个对象来进行数据转换。
@ResultMap
注解中的值命名方式是 #{Mapper对象全路径}.mybatis-plus_#{实体类名}
未添加@ResultMap
注解查询
涉及的类
@TableName(value = "user_table")
@Data
public class UserEntity {
private String name;
private Integer age;
@TableField(value = "table_desc",typeHandler = JacksonTypeHandler.class,jdbcType = JdbcType.OTHER)
private List<String> tableDesc;
}
@Mapper
public interface UserEntityMapper extends BaseMapper<UserEntity> {
@Select("select * from user_table ")
List<UserEntity> getAllValue();
}
@RestController
@RequestMapping("/test")
public class TestController {
@Resource
UserEntityMapper userEntityMapper;
@GetMapping("/query")
public String getQuery(){
return JSONObject.toJSONString(userEntityMapper.getAllValue());
}
}
查询结果
[
{ "age": 4, "name": "123" },
{ "age": 1, "name": "33333" }
]
添加@ResultMap
注解
涉及的类
@Mapper
public interface UserEntityMapper extends BaseMapper<UserEntity> {
@Select("select * from user_table ")
//命名方式是 ${Mapper对象全路径}.mybatis-plus_${实体类名}
@ResultMap("com.example.UserEntityMapper.mybatis-plus_UserEntity")
List<UserEntity> getAllValue();
}
查询结果
[
{ "age": 4, "name": "123", "tableDesc": [ "age", "123" ] },
{ "age": 1, "name": "33333", "tableDesc": [ "1123", "2131" ] }
]
原理分析
1、执行SQL
org.apache.ibatis.executor.statement.PreparedStatementHandler#query
方法中会执行SQL,获取查出的值
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyAutomaticMappings
方法中主要是对属性进行转换,此时autoMapping
只有两个基础字段的映射,并没有table_desc
字段的映射
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createAutomaticMappings
方法中会构造/获取当前方法相关的字段映射,key是方法方法全路径
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue
方法中可以看到mybatis的configuration
中resultMaps
对象中有4个键值对,其中
- 以方法名命名的是是没有属性映射的,所以在执行时复杂属性获取不到映射就不会进行赋值
- 以实体结尾的映射是由属性映射的,所以我们指定该值为
@ResultMap
内容就能对复杂对象进行赋值