如何在 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
方法,因为它可能取决于我们使用的环境
所以在我看来正确的实施应该是这样的:
- 创建
Enumerable
接口,所有持久化到数据库的枚举 class 都应该实现
- 每个枚举 class 都应该有创建方法,传递给它的序列化参数可以恢复枚举值
- 为 serialize/deserialize 枚举列表创建 kotlin 扩展
- 为每种类型的枚举创建类型转换器
因此,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
}
我的问题是如何存储
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
class EnumTypeConverter {
@TypeConverter
fun restoreEnum(enumName: String): EnumType = EnumType.valueOf(enumName)
@TypeConverter
fun saveEnumToString(enumType: EnumType) = enumType.name
}
让我展示 persisting/retrieving 使用 kotlin 的方法。
我们在操作过程中有什么限制?
- 我们将枚举列表作为字符串字段存储在数据库中,因此我们无法高效 select 或基于它在数据库中进行搜索
- 我们必须将每个枚举值序列化为字符串并将其反序列化回来
- 我们不能基于序号字段来防止将来由于扩展枚举而导致的错误,所以我们需要有一个常量字段来表示每个枚举值
- 我们不能基于列表到字符串的默认
toString
方法,因为它可能取决于我们使用的环境
- 我们不能基于列表到字符串的默认
所以在我看来正确的实施应该是这样的:
- 创建
Enumerable
接口,所有持久化到数据库的枚举 class 都应该实现 - 每个枚举 class 都应该有创建方法,传递给它的序列化参数可以恢复枚举值
- 为 serialize/deserialize 枚举列表创建 kotlin 扩展
- 为每种类型的枚举创建类型转换器
因此,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
}