如何在数据库室中保存枚举字段?

Posted

技术标签:

【中文标题】如何在数据库室中保存枚举字段?【英文标题】:How to save enum field in the database room? 【发布时间】:2019-12-11 02:23:52 【问题描述】:

我必须将enum 枚举中的值写入数据库。编译过程中发生错误。我做错了什么?

无法弄清楚如何将此字段保存到数据库中。您可以考虑为其添加类型转换器。

@ColumnInfo(name = "state_of_health")
@TypeConverters(HealthConverter::class)
var health: Health

enum class Health(val value: Int)
    NONE(-1),
    VERY_BAD(0),
    ...


class HealthConverter

    @TypeConverter
    fun fromHealth(value: Health): Int
        return value.ordinal
    

    @TypeConverter
    fun toHealth(value: Int): Health
        return when(value)
            -1 -> Health.NONE
            0 -> Health.VERY_BAD
            ...
            else -> Health.EXCELLENT
        
    


【问题讨论】:

看起来你应该用@TypeConverters 注释(而不是你的enum class)来注释你的Database 类。检查developer.android.com/training/data-storage/room/… @Demigod 是的,这是可行的。你可以写答案 【参考方案1】:

您可以对每个枚举进行转换,如下所示:

class Converters 

     @TypeConverter
     fun toHealth(value: String) = enumValueOf<Health>(value)

     @TypeConverter
     fun fromHealth(value: Health) = value.name

或者,如果您更喜欢将其存储为 SQL integer,您也可以使用 ordinal:

class Converters 

    @TypeConverter
    fun toHealth(value: Int) = enumValues<Health>()[value]

    @TypeConverter
    fun fromHealth(value: Health) = value.ordinal

不幸的是,没有办法使用泛型 Enum&lt;T&gt; 来完成此操作,因为未绑定的泛型会引发错误 Cannot use unbound generics in Type Converters

Android Room 团队可以认真地为他们的 kapt 编译器添加注解和枚举生成器。

最后,对一个数据库类、实体类、dao类、dao方法、dao方法参数或实体字段类进行注解:

@TypeConverters(Converters::class)

【讨论】:

如何在数据类中使用枚举?用值还是枚举? @Rafael 使用类型转换器后,你可以直接在你的实体类中使用枚举。【参考方案2】:

要解决此问题,请使用 @TypeConverters 注释(而不是 enum class)注释您的 Database 类。

例子:

@Database(entities = arrayOf(User::class), version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() 
    abstract fun userDao(): UserDao

查看https://developer.android.com/training/data-storage/room/referencing-data

【讨论】:

还有其他方法吗?在 JPA 中要容易得多。 @AllanVeloso,你想要什么作为“其他方式”?或者,您可以在模型中保存基本类型数据(例如枚举序号为Int,或枚举名称为String 等),但它会更好吗?还有,不知道JPA是什么... JPA = Java 持久性 API。它使用字段上的简单注释 @Enumerated(EnumType.STRING) 或 @Enumerated(EnumType.ORDINAL) 处理 Enum 类的持久性。这样你就不需要为每个枚举创建一个转换器。 @AllanVeloso,也许所有枚举都遵循一个接口可能会有所帮助。我已添加到我的答案中。 也不好,每次定义枚举选项时,都必须重写 getId() 方法。我尝试使用泛型、内联修饰和泛型。但是房间也不支持它,错误Cannot use unbound generics in Type Converters。最好手动转换。【参考方案3】:

这不再是version 2.3.0-alpha4 中的问题:“如果没有提供,Room 现在将默认使用 Enum 到 String 的类型转换器,反之亦然。如果枚举的类型转换器已经存在,Room 将优先使用它超过默认值。”

“如果 Enum 已经存在用于读取的单向类型转换器,Room 可能会意外使用内置的 String 到 Enum 转换器,这可能是不需要的。这是一个已知问题,可以通过将其设置为双向转换器。”

【讨论】:

【参考方案4】:

枚举类;

enum class Priority 
HIGH,
MEDIUM,
LOW

转换器类;

class Converter 

@TypeConverter
fun fromPriority(priority: Priority): String 
    return priority.name


@TypeConverter
fun toPriority(priority: String): Priority 
    return Priority.valueOf(priority)



用法;

@Database(entities = [MyData::class], version = 1, exportSchema = false)
@TypeConverters(Converter::class)
abstract class MyDatabase : RoomDatabase() 

  // todo


【讨论】:

“转换器”类是否可以包含您想要的所有转换器? @androiddeveloper 是的 @Milan Nice。谢谢你。【参考方案5】:

对于 Java 开发人员

枚举

public enum Health 
    NONE(-1),
    VERY_BAD(0);

    public final int value;

    Health(int newValue) 
        value = newValue;
    

    public int getValue() 
        return value;
    

类型转换器

public class HealthConverter 

    /**
     * Convert Health to an integer
     */
    @TypeConverter
    public static int fromHealthToInt(Health value) 
        return value.ordinal();
    

    /**
     * Convert an integer to Health
     */
    @TypeConverter
    public static Health fromIntToHealth(int value) 
        return (Health.values()[value]);
    


【讨论】:

【参考方案6】:

从 Room 版本 2.3.0 开始,您可以保存 Enum 看这里https://developer.android.com/jetpack/androidx/releases/room?hl=ru#version_230_3

【讨论】:

以上是关于如何在数据库室中保存枚举字段?的主要内容,如果未能解决你的问题,请参考以下文章

Android数据绑定:如何获取kotlin枚举类的字段值?

如何解决mysql enum 类型字段的插入问题

如何将mysql中枚举类型的数值在前台遍历为汉字

获取 Agora.io 语音讨论室中未发布流的用户列表

如何使用 Hibernate 将枚举值保存到 DB?

Grails:将枚举类型的mysql字段映射到域类