Room DAO查询报错:返回列缺少[time,value]非空字段问题求解
报错触发原因
该报错的核心触发原因有3点:
- Room默认不支持直接将自定义类型的List存储到单个字段中,你没有配置对应的TypeConverter的情况下,
timeAndValueList字段无法被正确序列化存储,查询返回的列结构和预期完全不符。 - Dao查询逻辑和返回类型不匹配:你写的查询是取出
timeAndValueList单个字段,但返回类型声明为List<TimeValueList>,Room会默认尝试将查询返回的每一行映射为TimeValueList对象,要求返回的列必须包含time、value两个字段,而你查询返回的只有单个序列化后的timeAndValueList字段,自然找不到对应列触发报错。 - 实体类和查询条件不匹配:你的
SignalDetails实体类中不存在signalName字段,但查询语句中添加了AND signalName = :name的过滤条件,本身属于语法错误,也会导致查询异常。
修复方案
基础修复(保留现有表结构)
- 第一步:添加TypeConverter支持自定义类型序列化
实现转换器类,将List<TimeValueList>和JSON字符串互相转换,示例代码如下(使用Gson实现):
class TimeValueListConverter { private val gson = Gson() @TypeConverter fun listToJson(list: List<TimeValueList>?): String? { return gson.toJson(list) } @TypeConverter fun jsonToList(json: String?): List<TimeValueList>? { return if (json.isNullOrEmpty()) { emptyList() } else { gson.fromJson(json, object : TypeToken<List<TimeValueList>>() {}.type) } } }
之后在你自定义的RoomDatabase类上添加注解注册转换器:
@Database(entities = [SignalDetails::class], version = 1) @TypeConverters(TimeValueListConverter::class) // 注册转换器 abstract class AppDatabase : RoomDatabase() { // 此处声明你的Dao }
第二步:修正实体类和查询条件的不匹配
二选一处理即可:- 如果确实需要按signalName过滤,在
SignalDetails类中添加val signalName: String字段,同时升级数据库版本 - 如果不需要该过滤条件,直接删掉Dao查询语句中的
AND signalName = :name部分,同时删掉方法参数中的name: Int
- 如果确实需要按signalName过滤,在
第三步:修正Dao方法的返回类型
timeAndValueList本身就是List<TimeValueList>类型,查询单条sessionId对应的记录直接返回该类型即可,修正后的Dao代码示例:
@Query("select timeAndValueList from VehicalSpeed WHERE sessionId = :id") fun getTimeAndValueList(id:Int): List<TimeValueList>?
优化方案(推荐)
如果你的业务场景需要频繁查询单条time/value记录,或者timeAndValueList数据量较大,建议拆分表结构,符合关系型数据库设计规范,也不需要配置TypeConverter:
- 新建
TimeValueEntity实体类,单条记录对应一个TimeValueList对象,添加关联字段sessionId - 直接查询
TimeValueEntity表过滤sessionId,返回List<TimeValueList>即可,查询效率更高。
内容的提问来源于stack exchange,提问作者Gaurav Kumar
相关产品推荐
相关产品推荐

