You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 16:31:19