首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MyBatis枚举用法

MyBatis枚举用法
EN

Stack Overflow用户
提问于 2012-04-19 06:53:27
回答 2查看 37.6K关注 0票数 17

我知道以前有人问过这个问题,但到目前为止,我还没能根据我找到的信息实现一个解决方案。所以也许有人能给我解释一下。

我有一个表“状态”。它有两列:id和name。id是一个主键。

我不想使用POJO状态,而是使用枚举。我创建了一个枚举,如下所示:

代码语言:javascript
复制
public enum Status {
    NEW(1), READY(2), CLOSED(3);

    private int id;

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    Status(int id) {
        this.id = id;
    }
}

这是我的映射器

代码语言:javascript
复制
     <select id="getStatusByName" resultType="Status" parameterType="String">       
        SELECT  ls.id, ls.name
        FROM status AS ls
        WHERE ls.name = #{name}
    </select>

但是由于某些原因,当我尝试检索枚举时,某些东西会中断,但没有抛出异常。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-06-08 08:53:03

我从几个角度研究了这个问题,以下是我的发现。注意:我使用MyBatis-3.1.1做了所有这些调查,所以在早期版本中可能会有不同的行为。

首先,MyBatis有一个内置的EnumTypeHandler。默认情况下,无论何时将Java enum指定为resultType或parameterType,这都将处理该类型。对于查询,当尝试将数据库记录转换为Java enum时,EnumTypeHandler只接受一个参数,并尝试查找与该值对应的Java enum值。

一个例子可以更好地说明这一点。假设当我传入"Ready“作为参数时,上面的查询返回2"Ready"。在这种情况下,我得到错误消息No enum constant com.foo.Status.2。如果我将SELECT语句的顺序颠倒为

代码语言:javascript
复制
SELECT ls.name, ls.id

则错误消息为No enum constant com.foo.Status.Ready。我假设你可以推断出MyBatis在做什么。请注意,EnumTypeHandler忽略了查询返回的第二个值。

将查询更改为

代码语言:javascript
复制
SELECT UPPER(ls.name)

使其工作:返回Status.READY枚举。

因此,接下来我尝试为状态枚举定义我自己的TypeHandler。不幸的是,与默认的枚举一样,我只能获取其中一个值(id或EnumTypeHandler )来引用正确的枚举,而不是两个都获取。因此,如果数据库id与上面硬编码的值不匹配,那么就会出现不匹配的情况。如果您确保数据库id总是与您在枚举中指定的id相匹配,那么您从数据库中所需要的就是名称(转换为大写)。

然后我想我会变得更聪明,实现一个MyBatis ObjectFactory,获取int和字符串名,并确保它们在我传递回的Java enum中匹配,但这并不起作用,因为MyBatis不会为Java enum类型调用ObjectFactory (至少我不能让它工作)。

因此,我的结论是,只要您只需要将数据库中的名称与枚举常量名称相匹配,MyBatis中的Java enum就很容易-要么使用内置的EnumTypeHandler,要么定义自己的名称(如果在SQL中执行UPPER(名称)不足以匹配Java enum名称)。在许多情况下,这就足够了,因为枚举值可能只是列上的检查约束,而且它只有一个值,没有id。如果还需要匹配int id和名称,那么在设置Java enum和/或数据库条目时手动匹配这些id。

最后,如果您想要看到这方面的工作示例,请参阅我的MyBatis koan中的Koan23:https://github.com/midpeter444/mybatis-koans。如果您只是想看看我的解决方案,请查看completed-koans/koan23目录。我还有一个通过Java枚举将记录插入数据库的示例。

票数 18
EN

Stack Overflow用户

发布于 2013-09-04 00:20:34

您可以使用自定义TypeHandler将结果直接转换为ENUM,这样就不需要将数据库中的所有值都作为大写ENUM名称。

这是状态枚举自定义处理程序的外观

代码语言:javascript
复制
public class StatusTypeHandler implements TypeHandler<Status> {

public Status getResult(ResultSet rs, String param) throws SQLException {
    return Status.getEnum(rs.getInt(param));
}

public Status getResult(CallableStatement cs, int col) throws SQLException {
    return Status.getEnum(cs.getInt(col));
}

public void setParameter(PreparedStatement ps, int paramInt, Status paramType, JdbcType jdbctype)
        throws SQLException {
    ps.setInt(paramInt, paramType.getId());
}
}

通过添加以下代码,在mybatis-config.xml中将TypeHandler定义为缺省处理状态。

代码语言:javascript
复制
    <typeHandlers> 
            <typeHandler javaType='Status' handler='StatusTypeHandler' /> 
    </typeHandlers>

现在让我们考虑一个示例,其中您的Dao中有以下两个函数,

代码语言:javascript
复制
Status getStatusById(int code);
Status getStatusByName(String name);

您的映射器将如下所示

代码语言:javascript
复制
<select id="getStatusById" resultType="Status" parameterType="int">       
    SELECT  ls.id
    FROM status AS ls
    WHERE ls.id = #{id}
</select>

<select id="getStatusByName" resultType="Status" parameterType="String">       
    SELECT  ls.id
    FROM status AS ls
    WHERE ls.name = #{name}
</select>

现在,由于两个映射器的resultType都是Status,myBatis将使用此类型的CustomTypeHandler,即StatusTypeHandler,而不是默认用于处理枚举的EnumTypeHandler,因此不需要在数据库中维护正确的枚举名称。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10219253

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档