Room数据库中如何通过legalName字段查询Person实体对象?
解决Room数据库中通过嵌套对象字段查询的问题
问题原因
Room默认不会自动解析嵌套的数据类字段,你的Person实体中name是Name类型的嵌套对象,数据库表中并不会生成name.legalName这样的层级列,因此直接用该语法查询会报错。
方案一:使用@Embedded注解展开嵌套字段(推荐)
通过@Embedded注解,Room会将嵌套对象的字段直接映射为数据库表的列,这样就能直接通过legalName字段查询。
修改实体类:
@Entity data class Person( @Embedded val name: Name, // 其他字段... ) data class Name( val legalName: String, val common: String )
修改DAO查询语句:
@Query("SELECT * FROM person WHERE legalName = :legalName") suspend fun getPersonByName(legalName: String): Person?
方案二:使用TypeConverter存储JSON格式(备选)
如果需要保留嵌套对象的结构,可以通过TypeConverter将Name转换为JSON字符串存储,再用SQL的JSON函数查询(仅支持Android API 26及以上)。
- 编写TypeConverter类:
class NameConverter { private val gson = com.google.gson.Gson() @androidx.room.TypeConverter fun fromName(name: Name): String = gson.toJson(name) @androidx.room.TypeConverter fun toName(nameJson: String): Name = gson.fromJson(nameJson, Name::class.java) }
- 在Room数据库类中注册转换器:
@androidx.room.Database(entities = [Person::class], version = 1) @androidx.room.TypeConverters(NameConverter::class) abstract class AppDatabase : androidx.room.RoomDatabase() { abstract fun personDao(): PersonDao }
- 修改查询语句:
@Query("SELECT * FROM person WHERE JSON_EXTRACT(name, '$.legalName') = :legalName") suspend fun getPersonByName(legalName: String): Person?
注意事项
- 方案一性能更优,且兼容性更好,优先选择。
- 如果存在多个嵌套对象可能导致列名冲突,可以给
@Embedded添加prefix参数,比如@Embedded(prefix = "name_"),此时查询字段变为name_legalName。
内容的提问来源于stack exchange,提问作者Chris Shafer
相关产品推荐
相关产品推荐

