当字段名称顺序更改时,mybatis resultMapping 不起作用

问题描述 投票:0回答:1

我将播放列表信息存储在 SQLite 数据库中。这是我的实体类;

@Data
@Builder
public class Playlist {
    private String id;
    private String playlistName;
    private PlaylistType type;
}

PlaylistType
是 ("TYPE_A", "TYPE_B") 的
enum

首先,在我的映射器 XML 中,我尝试使用

resultType="Playlist"
,并且当数据库列名称和
Playlist
属性处于相同顺序时它可以工作。但是如果我改变属性的顺序,例如如下所示,

public class Playlist {
    private String id;
    private PlaylistType type; // just moved PlaylistType property 
    private String playlistName;
}

它给了我这个错误:

Caused by: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'name' from result set.  Cause: java.lang.IllegalArgumentException: No enum constant com.example.demo.PlaylistType.p1

然后有些帖子建议使用

resultMap
,但问题仍然存在;

这是我使用

resultMap

的映射器 XML
<?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.example.demo.PlaylistRepository">

    <resultMap id="toPlaylist" type="com.example.demo.Playlist">
        <id column="id" property="id"/>
        <result column="name" property="playlistName"/>
        <result column="type" property="type"/>
    </resultMap>
    <select id="findById" resultMap="toPlaylist">
        select * from playlist where id = #{id}
    </select>
</mapper>

有没有更好的方法来映射数据库列?对于像实体类中属性的顺序这样的愚蠢问题,它不应该有太多限制。还是我错过了什么?

java mybatis spring-mybatis mybatis-mapper
1个回答
0
投票

我不敢相信我以稍微不同的方式犯了同样的错误。为了我和其他人的利益,让我分享一些见解。

这个问题看起来像是从mybatis中出现的,但事实并非如此。 Lombok 注释是导致问题的原因。本例中实际的映射操作可以追溯到

private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException { for (int i = 0; i < constructor.getParameterTypes().length; i++) { Class<?> parameterType = constructor.getParameterTypes()[i]; String columnName = rsw.getColumnNames().get(i); TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName); Object value = typeHandler.getResult(rsw.getResultSet(), columnName); constructorArgTypes.add(parameterType); constructorArgs.add(value); foundValues = value != null || foundValues; } return foundValues; }

来自 org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java#L783

可以看出,构造函数参数是一一获取的,因此实体类中属性的顺序很重要。这是因为

@Builder

 注释将创建一个全参数构造函数。因此,mybatis 无法使用 
reflection
 来映射参数,因为它没有默认构造函数(此检查在 DefaultResultSetHandler.java
的第 686 行完成)。相反,它会迭代构造函数参数并设置值。这就是为什么顺序很重要。 解决方案很简单,只需在

@NoArgsConstructor

类之上添加

@AllArgsConstructor
Playlist
即可。
    

© www.soinside.com 2019 - 2024. All rights reserved.