Java Mybatis使用resultMap时,属性赋值顺序错误的巨坑
作者:百事可乐_
Mybatis使用resultMap属性赋值顺序错误
今天发现个坑,新建的表使用生成工具生成的mapper文件和实体类后,发现少了个字段就又手动加了下,结果发现一个问题
ids是后加入的字段
@Data @Builder public class QueryRecordPo { //若干其他属性.... private String outputField; //后加的 private String ids; //若干其他属性 //... }
resultMap中是这样写的
<resultMap id="BaseResultMap" type="...."> <id column="id" jdbcType="BIGINT" property="id"/> ..若干其他属性 <result column="ids" jdbcType="VARCHAR" property="ids"/> <result column="output_field" jdbcType="VARCHAR" property="outputField"/> ..若干其他属性 </resultMap>
可以发现ids加的位置是不一样的,实体类中在outputField属性下面,但resultMap中在其上面。然后测试数据中ids字段为null,查询出来时却发现ids的值和outputField的值是一样的。但如果ids的字段有值,就可以正确赋值。
mybatis在生成目标类进行映射时,会先检查构造函数声明情况,但 如果Data注解和Builder注解一块使用的话就只会生成全属性参数构造函数,不会有默认无参构造函数。全属性构造函数的参数顺序是和类中属性声明顺序一致的
在把数据库字段映射到实体类的时候发现实体类没有默认无参构造函数,就会把数据库中的字段按照全属性构造函数参数的顺序依次赋值给实体类的属性。但如果实体类的属性定义顺序与数据库中字段顺序不一致,就会出现赋值错误的情况。
然后再为outputField字段赋值时调用了set方法 这样就出现了两个不同名但同值的属性。
解决办法
1 修改属性顺序保持一致
2 为实体类加上@NoArgsConstructor和 @AllArgsConstructor注解 使其可以生成无参数构造函数即可
之前生成时 顺序都保持了一致,还真没发现这个问题
Mybatis使用resultMap时需注意
<resultMap id="baseMap" type="com.ei.medical.modules.model.EduEducationKnowledge"> <id column="id" property="id"/> <result column="visitNumber" property="visitNumber"/> <result column="patientName" property="patientName"/> <result column="sendTime" property="sendTime"/> <result column="wardCode" property="wardCode"/> <result column="wardName" property="wardName"/> <result column="categoryCode" property="categoryCode"/> <result column="title" property="title"/> <result column="content" property="content"/> <result column="cover" property="cover"/> </resultMap> <select id="getAllBy" resultMap="baseMap"> SELECT eer.visit_number as visitNumber, eer.patient_name as patientName, eer.send_time as sendTime, eek.id as id, eek.ward_code as wardCode, eek.ward_name as wardName, eek.category_code as categoryCode, eek.title as title, eek.content as content, eek.cover as cover FROM edu_education_record AS eer, edu_education_knowledge AS eek WHERE eer.education_knowledge_id=eek.id </select>
如果是实体中是直接引用别的对象的具体参数字段,直接用原始方式就行
如果是实体中是list集合
<resultMap id="baseMap" type="com.ei.medical.modules.model.EduEducationKnowledge"> <id column="id" property="id"/> <result column="visitNumber" property="visitNumber"/> <result column="patientName" property="patientName"/> <result column="sendTime" property="sendTime"/> <result column="wardCode" property="wardCode"/> <result column="wardName" property="wardName"/> <result column="categoryCode" property="categoryCode"/> <result column="title" property="title"/> <result column="content" property="content"/> <result column="cover" property="cover"/> <collection property="pic" ofType="string"> <result column="pic"/> </collection> </resultMap> <select id="getAllBy" resultMap="baseMap"> SELECT eer.visit_number as visitNumber, eer.patient_name as patientName, eer.send_time as sendTime, eek.id as id, eek.ward_code as wardCode, eek.ward_name as wardName, eek.category_code as categoryCode, eek.title as title, eek.content as content, eek.cover as cover FROM edu_education_record AS eer, edu_education_knowledge AS eek WHERE eer.education_knowledge_id=eek.id </select>
如果实体中引用的是别的对象,可以使用association 标签来写
<resultMap id="baseMap" type="com.ei.medical.modules.model.EduEducationKnowledge"> <id column="id" property="id"/> <result column="wardCode" property="wardCode"/> <result column="wardName" property="wardName"/> <result column="categoryCode" property="categoryCode"/> <result column="title" property="title"/> <result column="content" property="content"/> <result column="cover" property="cover"/> <association property="eduEducationRecord" javaType="com.ei.medical.modules.model.EduEducationRecord"> <result column="visitNumber" property="visitNumber"/> <result column="patientName" property="patientName"/> <result column="sendTime" property="sendTime"/> </association> </resultMap> <select id="getAllBy" resultMap="baseMap"> SELECT eer.visit_number as visitNumber, eer.patient_name as patientName, eer.send_time as sendTime, eek.id as id, eek.ward_code as wardCode, eek.ward_name as wardName, eek.category_code as categoryCode, eek.title as title, eek.content as content, eek.cover as cover FROM edu_education_record AS eer, edu_education_knowledge AS eek WHERE eer.education_knowledge_id=eek.id </select>
如果实体中是引用的别的对象的list集合,应该使用collection 标签
<resultMap id="baseMap" type="com.ei.medical.modules.model.EduEducationKnowledge"> <id column="id" property="id"/> <result column="wardCode" property="wardCode"/> <result column="wardName" property="wardName"/> <result column="categoryCode" property="categoryCode"/> <result column="title" property="title"/> <result column="content" property="content"/> <result column="cover" property="cover"/> <collection property="eduEducationRecordList" ofType="com.ei.medical.modules.model.EduEducationRecord"> <result column="visitNumber" property="visitNumber"/> <result column="patientName" property="patientName"/> <result column="sendTime" property="sendTime"/> </collection> </resultMap> <select id="getAllBy" resultMap="baseMap"> SELECT eer.visit_number as visitNumber, eer.patient_name as patientName, eer.send_time as sendTime, eek.id as id, eek.ward_code as wardCode, eek.ward_name as wardName, eek.category_code as categoryCode, eek.title as title, eek.content as content, eek.cover as cover FROM edu_education_record AS eer, edu_education_knowledge AS eek WHERE eer.education_knowledge_id=eek.id </select>
tips:
使用resultMap的时候,应该直接用as后面的字段名,即自己命的名字
如果没有使用as的话,直接使用数据库中原本的名字
resultMap中各个标签的含义
tips:
在一个 resultMap 元素中,这些子元素出现的先后顺序是有严格规定的,它们从前到后依次是:constructor–>id --> result–> association–>collection -->discriminator, 不然就会报错。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。