Kotlin中Room Entity与Data Class互转及报错解决
Exchange数据类存入Room数据库的问题解决
问题说明
从网络获取了Exchange数据类,尝试存入Room数据库时出现报错,同时在Repository的getAll()方法中无法将ExchangeEntity正确转换为Exchange对象,另外编写的类型转换器也不确定是否正确。
相关代码
Room实体类
@Entity(tableName = "ExchangeValues") data class ExchangeEntity( @ColumnInfo(name = "base_code") val base_code: String, @ColumnInfo(name = "conversion_rates") val conversion_rates: ConversionRates, @ColumnInfo(name = "result") val result: String, @PrimaryKey(autoGenerate = true) val uid: Int? = null )
Dao接口
@Dao interface ExchangeDao { @Query("SELECT * FROM ExchangeValues") suspend fun getAll(): List<ExchangeEntity> @Query("UPDATE ExchangeValues SET base_code=:base_code, conversion_rates=:conversion_rates, result=:result") suspend fun update(base_code: String, conversion_rates: ConversionRates, result: String) }
Exchange数据类
@Serializable data class Exchange( val base_code: String, val conversion_rates: ConversionRates, val documentation: String, val result: String, val terms_of_use: String, val time_last_update_unix: Int, val time_last_update_utc: String, val time_next_update_unix: Int, val time_next_update_utc: String ) { fun toEntity() = ExchangeEntity( base_code = base_code, conversion_rates = conversion_rates, result = result ) } @Serializable data class ConversionRates( val conversionRates: Map<String, Double> )
ExchangeRepositoryImpl实现
class ExchangeRepositoryImpl @Inject constructor( private val dao: ExchangeDao ) : ExchangeRepository { override suspend fun getAll(): Flow<List<Exchange>> { return flow { emit(dao.getAll()) } } override suspend fun update(exchange: Exchange) { dao.update(exchange.base_code, exchange.result, exchange.conversion_rates) } }
类型转换器
class ExchangeConverter { @TypeConverter fun fromSource(conversionRates: ConversionRates): String { val gson = Gson() return gson.toJson(conversionRates) } @TypeConverter fun toSource(json: String): ConversionRates { val gson = Gson() val typeToken = object : TypeToken<List<ConversionRates>>() {}.type return Gson().fromJson(json, typeToken) } }
解决方案
1. 修复类型转换器的错误
当前toSource方法错误使用了List<ConversionRates>的TypeToken,但实际存储的是单个ConversionRates对象,需要修正TypeToken类型,同时要让Room识别该转换器:
// 修正后的转换器 class ExchangeConverter { @TypeConverter fun fromSource(conversionRates: ConversionRates): String { return Gson().toJson(conversionRates) } @TypeConverter fun toSource(json: String): ConversionRates { val typeToken = object : TypeToken<ConversionRates>() {}.type return Gson().fromJson(json, typeToken) } }
在Room Database类上添加注解,注册转换器:
@Database(entities = [ExchangeEntity::class], version = 1) @TypeConverters(ExchangeConverter::class) abstract class AppDatabase : RoomDatabase() { abstract fun exchangeDao(): ExchangeDao }
2. 修复Repository的getAll()转换逻辑
dao.getAll()返回List<ExchangeEntity>,需要将其转换为List<Exchange>。由于原ExchangeEntity缺少Exchange的部分字段,有两种处理方式:
方式一:扩展ExchangeEntity字段(推荐)
修改ExchangeEntity补全所有Exchange字段,确保数据完整:@Entity(tableName = "ExchangeValues") data class ExchangeEntity( @ColumnInfo(name = "base_code") val base_code: String, @ColumnInfo(name = "conversion_rates") val conversion_rates: ConversionRates, @ColumnInfo(name = "documentation") val documentation: String, @ColumnInfo(name = "result") val result: String, @ColumnInfo(name = "terms_of_use") val terms_of_use: String, @ColumnInfo(name = "time_last_update_unix") val time_last_update_unix: Int, @ColumnInfo(name = "time_last_update_utc") val time_last_update_utc: String, @ColumnInfo(name = "time_next_update_unix") val time_next_update_unix: Int, @ColumnInfo(name = "time_next_update_utc") val time_next_update_utc: String, @PrimaryKey(autoGenerate = true) val uid: Int? = null )更新
Exchange的toEntity()方法:fun toEntity() = ExchangeEntity( base_code = base_code, conversion_rates = conversion_rates, documentation = documentation, result = result, terms_of_use = terms_of_use, time_last_update_unix = time_last_update_unix, time_last_update_utc = time_last_update_utc, time_next_update_unix = time_next_update_unix, time_next_update_utc = time_next_update_utc )给
ExchangeEntity添加反向转换方法:fun toExchange() = Exchange( base_code = base_code, conversion_rates = conversion_rates, documentation = documentation, result = result, terms_of_use = terms_of_use, time_last_update_unix = time_last_update_unix, time_last_update_utc = time_last_update_utc, time_next_update_unix = time_next_update_unix, time_next_update_utc = time_next_update_utc )最后修改Repository的
getAll():override suspend fun getAll(): Flow<List<Exchange>> { return flow { emit(dao.getAll().map { it.toExchange() }) } }方式二:给缺失字段设默认值
如果不需要完整Exchange对象,转换时给缺失字段设默认值:override suspend fun getAll(): Flow<List<Exchange>> { return flow { emit(dao.getAll().map { entity -> Exchange( base_code = entity.base_code, conversion_rates = entity.conversion_rates, documentation = "", result = entity.result, terms_of_use = "", time_last_update_unix = 0, time_last_update_utc = "", time_next_update_unix = 0, time_next_update_utc = "" ) }) } }
3. 修复Dao的update方法(添加WHERE条件)
原update语句无WHERE条件,会更新表中所有行,需添加条件指定更新的记录:
@Query("UPDATE ExchangeValues SET base_code=:base_code, conversion_rates=:conversion_rates, result=:result WHERE uid=:uid") suspend fun update(uid: Int, base_code: String, conversion_rates: ConversionRates, result: String)
修改Repository的update方法,传入对应uid:
override suspend fun update(exchange: Exchange, uid: Int) { dao.update(uid, exchange.base_code, exchange.conversion_rates, exchange.result) }
4. 修复Repository的update方法参数顺序
原调用dao.update时参数顺序错误,导致字段赋值混乱,修正顺序:
override suspend fun update(exchange: Exchange) { dao.update(exchange.base_code, exchange.conversion_rates, exchange.result) }
内容的提问来源于stack exchange,提问作者NewPartizal
相关产品推荐
相关产品推荐

