如何在 RoomDatabase 中存储 Enum 的 ArrayList

How to store ArrayList of Enum in RoomDatabase

我的问题是如何存储

List<Enum>

在房间数据库中, 到目前为止,我找不到答案。

将您的枚举序列化为整数并存储它们。

检索值时,执行反向操作。

这两个操作在我对这个问题的回答中都有解释:

How to match int to enum

枚举:

public enum HelloEnum {
    A,
    B,
    C
}

转换器:

public class EnumConverter {

    @TypeConverter
    public List<HelloEnum> storedStringToEnum(String value) {
        List<String> dbValues = Arrays.asList(value.split("\s*,\s*"));
        List<HelloEnum> enums = new ArrayList<>();

        for (String s: dbValues)
            enums.add(HelloEnum.valueOf(s));

        return enums;
    }

    @TypeConverter
    public String languagesToStoredString(List<HelloEnum> cl) {
        String value = "";

        for (HelloEnum lang : cl)
            value += lang.name() + ",";

        return value;
    }    
}

就插入和获取数据而言,这将有效而不是提问。

@Dao
public interface HelloPojoDao {

    @Query("SELECT * FROM helloPojo")
    List<HelloPojo> fetchAll();

    @Insert
    void insertPojo(HelloPojo pojo);
}

不过,我要指出的是,现在通过枚举进行过滤变得有点棘手了。例如,如果您想编写一个查询来获取包含 enum.A 和 enum.B 的对象,您将必须构建一个查询来为它们查询一个字符串对象。在这种情况下,“SELECT * FROM pojo WHERE enums contains 'A,' and 'B,'。因此,最好将数字值分配给您的枚举(如@Kuffs 回答详细信息),因为解析整数可能会产生的问题比解析字符串少。

希望这能解决您的问题。有什么问题欢迎在评论区提问,祝狩猎愉快!

好的,当使用 name

时,使用 Kotlin 就简单多了
class EnumTypeConverter {

    @TypeConverter
    fun restoreEnum(enumName: String): EnumType = EnumType.valueOf(enumName)

    @TypeConverter
    fun saveEnumToString(enumType: EnumType) = enumType.name
}

让我展示 persisting/retrieving 使用 kotlin 的方法。

我们在操作过程中有什么限制?

  • 我们将枚举列表作为字符串字段存储在数据库中,因此我们无法高效 select 或基于它在数据库中进行搜索
  • 我们必须将每个枚举值序列化为字符串并将其反序列化回来
  • 我们不能基于序号字段来防止将来由于扩展枚举而导致的错误,所以我们需要有一个常量字段来表示每个枚举值
    • 我们不能基于列表到字符串的默认toString方法,因为它可能取决于我们使用的环境

所以在我看来正确的实施应该是这样的:

  1. 创建 Enumerable 接口,所有持久化到数据库的枚举 class 都应该实现
  2. 每个枚举 class 都应该有创建方法,传递给它的序列化参数可以恢复枚举值
  3. 为 serialize/deserialize 枚举列表创建 kotlin 扩展
  4. 为每种类型的枚举创建类型转换器

因此,Enumerable 接口:

/** marks the enum with custom int code for each value */
interface Enumerable {
    val code: Int
}

枚举示例:

enum class PaymentSystemEntity constructor(
    override val code: Int
) : Enumerable {
    VISA(1),
    MASTERCARD(2),
    UNKNOWN(0);

    companion object {
        fun parseFromCode(code: Int): PaymentSystemEntity = values()
            .firstOrNull { it.code == code } ?: UNKNOWN
    }

}

序列化扩展:

fun <T> List<T>.asString(): String where T : Enum<T>, T : Enumerable = this
    .map { it.code }
    .joinToString(separator = ",")

fun <T> String.toEnumList(creator: (code: Int) -> T): List<T> where T : Enum<T>, T : Enumerable = this
    .split(',')
    .map { it.toInt() }
    .map { creator(it) }

枚举的样本类型转换器:

class PaymentSystemTypeConverter {

    @TypeConverter
    fun paymentSystemsToString(value: List<@JvmSuppressWildcards PaymentSystemEntity>): String =
         value.asString()

    @TypeConverter
    fun stringToPaymentSystems(value: String): List<@JvmSuppressWildcards PaymentSystemEntity> =
        value.toEnumList { PaymentSystemEntity.parseFromCode(it) }

}

您可能有以相同方式实现的其他类型的集合

Kotlin 中的 Jack Dalton 版本:

@TypeConverter
fun storedStringListLineType(value: String): List<LineType> {
    val dbValues = value.split("\s*,\s*".toRegex()).dropLastWhile { it.isEmpty() }
    val enums: MutableList<LineType> = ArrayList()

    for (s in dbValues)
        enums.add(LineType.valueOf(s))
    return enums
}

@TypeConverter
fun listLineTypeToStoredString(listLineTypes: List<LineType>): String {
    var value = ""

    for (lineType in listLineTypes)
        value += lineType.name + ","

    return value
}