¿Cómo guardar el campo de enumeración en la sala de la base de datos?

4 minutos de lectura

Debo escribir el valor de la enum enumeración a la base de datos. Se produce un error durante la compilación. ¿Qué estoy haciendo mal?

No se puede averiguar cómo guardar este campo en la base de datos. Puede considerar agregar un convertidor de tipos para ello.

@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
        }
    }

}

Avatar de usuario de Allan Veloso
allan veloso

Puede hacer una conversión a cada enumeración, así:

class Converters {

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

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

O si prefiere almacenarlo como SQL integertambién puedes usar ordinal:

class Converters {

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

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

Desafortunadamente, no hay forma de usar genéricos Enum<T> para lograr esto, ya que los genéricos no vinculados generarán un error Cannot use unbound generics in Type Converters.

El equipo de Android Room podría agregar seriamente una anotación y un generador para Enums a su compilador kapt.

Finalmente, anote una clase de base de datos, clase de entidad, clase dao, método dao, parámetro de método dao o clase de campo de entidad con esto:

@TypeConverters(Converters::class)

  • ¿Cómo usar la enumeración en la clase de datos? Con el valor o enumeración?

    – Rafael

    12 de noviembre de 2020 a las 15:50

  • @Rafael Después de usar el convertidor de tipos, puede usar directamente la enumeración en su clase de entidad.

    – Sarthak_ssg5

    30 de octubre de 2021 a las 5:03

Esto ya no es un problema en versión 2.3.0-alpha4: “Room ahora usará de forma predeterminada un convertidor de tipo Enum a String y viceversa si no se proporciona ninguno. Si ya existe un convertidor de tipo para una enumeración, Room priorizará su uso sobre el predeterminado”.

“Si ya existe un convertidor de tipo unidireccional para lectura para el Enum, Room podría usar accidentalmente el convertidor de cadena a Enum incorporado que podría no ser deseado. Este es un problema conocido y se puede solucionar convirtiéndolo en un convertidor bidireccional convertidor.”

Avatar de usuario de Semidiós
Semidiós

Para arreglar esto, anote su Database clase con @TypeConverters anotación (y no su enum class).

Ejemplo:

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

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

  • ¿Hay alguna otra manera? En JPA es mucho más fácil.

    – Alan Veloso

    1 de febrero de 2020 a las 16:50

  • @AllanVeloso, ¿qué quieres tener como “otro camino”? Alternativamente, puede contener datos de tipo básico en sus modelos (como enum ordinal como Into enum nombre como String, etc.), pero ¿será mejor? Además, no sé qué es el JPA …

    – Semidiós

    3 de febrero de 2020 a las 11:31

  • JPA = API de persistencia de Java. Maneja la persistencia de las clases Enum con una simple anotación @Enumerated(EnumType.STRING) o @Enumerated(EnumType.ORDINAL) en el campo. De esta manera, no necesita crear un convertidor para cada enumeración.

    – Alan Veloso

    3 de febrero de 2020 a las 23:06

  • @AllanVeloso, tal vez seguir una sola interfaz por todas las enumeraciones es lo que podría ayudar. He agregado a mi respuesta.

    – Semidiós

    4 de febrero de 2020 a las 10:43

  • Tampoco es bueno, cada vez que defina una opción de enumeración, tendrá que anular el método getId(). Traté de usar genéricos, rectificados en línea y genéricos. pero room tampoco lo soporta, error Cannot use unbound generics in Type Converters. Mejor convertirlo manualmente.

    – Alan Veloso

    5 de febrero de 2020 a las 15:16

clase de enumeración;

enum class Priority {
HIGH,
MEDIUM,
LOW
}

Clase de convertidor;

class Converter {

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

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

}

uso;

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

  // todo

}

Avatar de usuario de Zain
Zain

Para desarrolladores java

La enumeración

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

    public final int value;

    Health(int newValue) {
        value = newValue;
    }

    public int getValue() {
        return value;
    }
}

El convertidor de tipos

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]);
    }

}

Avatar de usuario de Waran-
Waran-

Desde la versión 2.3.0 de Room puedes guardar Enum Look aquí https://developer.android.com/jetpack/androidx/releases/room?hl=ru#version_230_3

¿Ha sido útil esta solución?