org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'femaleHealthForm' of 'class com.ss.learn.chapter5.pojo.FemaleHealthForm' with value '[FemaleHealthForm [id=1, heart=1, liver=1, spleen=1, lung=1, kidney=1, uterus=1, note=1111]]' Cause: org.apache.ibatis.reflection.ReflectionException: There is no setter for property named 'femaleHealthForm' in 'class com.ss.learn.chapter5.pojo.FemaleHealthForm'
### The error may exist in com/ss/learn/chapter5/mapper/FemaleHealthFormMapper.xml
### The error may involve com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId
### The error occurred while handling results
### SQL: select id, heart, liver, spleen, lung, kidney, uterus, note from t_female_health_form where emp_id = ?
### Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'femaleHealthForm' of 'class com.ss.learn.chapter5.pojo.FemaleHealthForm' with value '[FemaleHealthForm [id=1, heart=1, liver=1, spleen=1, lung=1, kidney=1, uterus=1, note=1111]]' Cause: org.apache.ibatis.reflection.ReflectionException: There is no setter for property named 'femaleHealthForm' in 'class com.ss.learn.chapter5.pojo.FemaleHealthForm'
在用Mybatis的鉴别器<discriminator>时出现的异常,大致意思是,在A类里,没有属性B的setter方法。也就是说,检索出来的的值不能放进POJO的A的属性B中。一般情况是:
①在类A中没有添加B属性,或没有setter方法,那么持久层检索出来的数据无法跟POJO映射上
②类A的属性名和配置文件里的不一致,这是由粗心导致的
解决的关键就是:把漏的属性填上,在配置xml文件的时候要细心,property和column的值要分别于属性和列名对应上。
③resultMap里的type属性填错了。这个是把自己困扰4小时的低级错误,打个比方:类A的属性之一是类B。那么用级联,通过类A的某一个属性检索出类B对象。resultMap填的应该是类A的全限定名或者别名,因为类A里才有属性类B来接收检索出类B的数据。
记一下昨晚用<discriminator>时配置文件中<resultMap>的type的错误:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ss.learn.chapter5.mapper.EmployeeMapper">
<resultMap type="Employee" id="employeeResultMap">
<id property="empId" column="emp_id"/>
<result property="realName" column="real_name"/>
<result property="sex" column="sex" typeHandler="com.ss.learn.chapter4.typehandler.SexEnumTypeHandler"/>
<result property="birthday" column="birthday"/>
<result property="mobile" column="mobile"/>
<result property="email" column="email"/>
<result property="position" column="position"/>
<result property="note" column="note"/>
<association property="workCard" column="emp_id" select="com.ss.learn.chapter5.mapper.WorkCardMapper.getWorkCardByEmpId"></association>
<collection property="employeeTaskList" column="emp_id" select="com.ss.learn.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"></collection>
<discriminator javaType="long" column="sex">
<case value="0" resultMap="femaleHealthFormResultMapper"/>
<case value="1" resultMap="maleHealthFormResultMapper"/>
</discriminator>
</resultMap>
<resultMap type="femaleHealthForm" id="femaleHealthFormResultMapper" extends="employeeResultMap">
<association property="femaleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId"></association>
</resultMap>
<resultMap type="maleEmployee" id="maleHealthFormResultMapper" extends="employeeResultMap">
<association property="maleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.MaleHealthFormMapper.getMaleHealthFormByEmpId"></association>
</resultMap>
<select id="getEmployeeByEmpId" parameterType="Long" resultMap="employeeResultMap">
select emp_id, real_name, sex, birthday, mobile, email, position, note
from t_employee
where emp_id = #{empId}
</select>
</mapper>
错误的地方在:
<resultMap type="femaleHealthForm" id="femaleHealthFormResultMapper" extends="employeeResultMap">
<association property="femaleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId"></association>
</resultMap>
type属性填的与association元素的property一样,检索出的都已经是类B了,resultMap里的type填的又是类B,类B里当然没有属性B来接收检索出的类B的数据了啊,所以会报异常,there is no setter for property named "B" in "B", 在类B里没属性B。
改成:
<resultMap type="femaleEmployee" id="femaleHealthFormResultMapper" extends="employeeResultMap">
<association property="femaleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId"></association>
</resultMap>
整个关于association collection discriminator的代码就调通了。
后记:
在映射器的XML文件中的resultMap的extends属性与它们类的关系相似:B、C继承A而来,那么B、C的resultMap也可以继承A而来。在A的resultMap里写通用属性的映射,B、C的resultMap里写特有的属性的映射,然后继承A的resultMap。同时注意一点,B、C的resultMap的type就是类B和类C,映射的POJO就是B、C,而被继承的A的type就被B、C覆盖了。
比如:
<resultMap type="Employee" id="employeeResultMap">
<id property="empId" column="emp_id"/>
<result property="realName" column="real_name"/>
<result property="sex" column="sex" typeHandler="com.ss.learn.chapter4.typehandler.SexEnumTypeHandler"/>
<result property="birthday" column="birthday"/>
<result property="mobile" column="mobile"/>
<result property="email" column="email"/>
<result property="position" column="position"/>
<result property="note" column="note"/>
<association property="workCard" column="emp_id" select="com.ss.learn.chapter5.mapper.WorkCardMapper.getWorkCardByEmpId"></association>
<collection property="employeeTaskList" column="emp_id" select="com.ss.learn.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"></collection>
<discriminator javaType="long" column="sex">
<case value="0" resultMap="femaleEmployeeResultMap"/>
<case value="1" resultMap="maleEmployeeResultMap"/>
</discriminator>
</resultMap>
<resultMap type="femaleEmployee" id="femaleEmployeeResultMap" extends="employeeResultMap">
<association property="femaleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId"></association>
</resultMap>
<resultMap type="maleEmployee" id="maleEmployeeResultMap" extends="employeeResultMap">
<association property="maleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.MaleHealthFormMapper.getMaleHealthFormByEmpId"></association>
</resultMap>
当sex的值为0时,映射到femaleEmployeeResultMap,femaleEmployeeResultMap是继承EmployeeResultMap而来。
相当于,用了一个以下的映射
<resultMap type="femaleEmployee" id="femaleEmployeeResultMap">
<id property="empId" column="emp_id"/>
<result property="realName" column="real_name"/>
<result property="sex" column="sex" typeHandler="com.ss.learn.chapter4.typehandler.SexEnumTypeHandler"/>
<result property="birthday" column="birthday"/>
<result property="mobile" column="mobile"/>
<result property="email" column="email"/>
<result property="position" column="position"/>
<result property="note" column="note"/>
<association property="workCard" column="emp_id" select="com.ss.learn.chapter5.mapper.WorkCardMapper.getWorkCardByEmpId"></association>
<collection property="employeeTaskList" column="emp_id" select="com.ss.learn.chapter5.mapper.EmployeeTaskMapper.getEmployeeTaskByEmpId"></collection>
<association property="femaleHealthForm" column="emp_id" select="com.ss.learn.chapter5.mapper.FemaleHealthFormMapper.getFemaleHealthFormByEmpId"></association>
</resultMap>