保存到 Room 时数据类型为 false
Data type false when saving to Room
我正在用 Kotlin 编写 android 应用程序。尝试使用 room 将数据保存到本地存储。
但是我有一个错误:“无法弄清楚如何将这个字段保存到数据库中。你可以考虑为它添加一个类型转换器”。
我尝试根据文档并借助 Stack Overflow 上的示例将转换器转换为字符串。但我仍然有同样的错误。请告诉我如何避免它。
这是我的 class 我形成结构的地方:
data class Request(
val method: String?,
val url: String?,
val headers: Map<String, List<String>>?,
val body: String,
val size: Int,
)
data class Response(
val code: Int?,
val headers: Map<String, List<String>>?,
val body: String?,
val size: Int?,
)
@Entity
data class Packet(
@PrimaryKey val id: Int,
val userId: String,
val deviceId: String,
val sessionId: String,
val timestamp: Long?,
val duration: Int?,
val protocol: String?,
@Embedded val request: Request?,
@Embedded val response: Response?,
)
这就是我保存数据的方式
@Database(
version = 1,
entities = [Packet::class]
)
abstract class NetworkDatabase : RoomDatabase() {
abstract fun packetDao(): PacketDao
}
SQLite(room 是包装器的关系数据库)仅限于 table(@Entity 注释 class)具有可以包含单个值的列仅限于一小组类型(TEXT(String) INTEGER(Int,Long,....) REAL(Float,Double,....) BLOB(ByteArray) 和 NUMERIC(Room 不可用))
As Such youMap<String, List<String>>
无法直接存储。您需要将其转换为单个值或更正确,在列表的情况下,在数据库术语中另一个 table。但是,通常会放弃使用 table 以更方便地转换为单个值,通常是将 object(s) 表示为字符串的 JSON 字符串。
Room 通过使用两个注释 @TypeConverter
和 @TypeConverters
来促进 TypeConverter 的使用
- 前者先于执行从 object 到受支持值的转换的函数,并且始终是执行相反操作的补充函数。
- 第二个定义包含函数及其作用域的 classes。
所以你需要有带@TypeConvert 注释的函数和一个带 suitable 范围的@TypeConverters(在@Database 级别给出了最广泛的范围)。
当您在数据包中嵌入请求和响应时 classes (table)。您还会遇到列命名问题,因为 headers、body 和大小 variables/fields 具有相同的名称。
此外,如果使用 JSON 字符串进行最方便的转换,List、Maps 和 Arrays 处理起来会有点困难。控股class可以简化事情。
1).由于 JSON 将用于从 object 转换为 JSON 字符串,因此您应该为 com.google.code.gson 添加依赖项,例如implementation 'com.google.code.gson:gson:2.9.0'
到您的构建 gradle(模块)。
- 还有其他选择
2).修改 classes 以便 variable/field 名称不会与列名称重复,并另外为地图引入一个控股 class (一个适合 Response 和 Request classes) .所以 classes 可能是 :-
/* Holding Class */
data class Mapping (
val header: Map<String, List<String>>
)
/* Note changed column names */
data class Request(
val requestMethod: String?,
val requestUrl: String?,
val requestHeaders: Mapping?,
val requestBody: String,
val requestSize: Int
)
/* Note changed column names */
data class Response(
val responseCode: Int?,
val responseHeaders: Mapping?,
val responseBody: String?,
val responseSize: Int?
)
@Entity
data class Packet(
@PrimaryKey val id: Int,
val userId: String,
val deviceId: String,
val sessionId: String,
val timestamp: Long?,
val duration: Int?,
val protocol: String?,
@Embedded val request: Request?,
@Embedded val response: Response?
)
3).为 TypeConverter 函数添加一个 class,将持有(映射)class to/from 转换为 object 的 JSON 字符串表示,例如:-
class RoomTypeConverters {
@TypeConverter
fun fromMappingToJSONString(mapping: Mapping): String {
return Gson().toJson(mapping)
}
@TypeConverter
fun fromJSONStringToMapping(jsonString: String): Mapping {
return Gson().fromJson(jsonString,Mapping::class.java)
}
}
4).添加具有 suitable 范围的 @TypeConverters 注释,完整范围在 @Database 级别,因此注释为 class 的 @Database 可以是 :-
@TypeConverters(value = [RoomTypeConverters::class]) //<<<<<<<<<< defines the classes that include the @TypeConverter annotated functions
@Database(entities = [Packet::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
....
}
使用上面的方法构建成功,例如
Executing tasks: [:app:assembleDebug] in project E:\AndroidStudioApps\SO72128161KotlinRoomTypeConverters
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs NO-SOURCE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:kaptGenerateStubsDebugKotlin
> Task :app:kaptDebugKotlin
> Task :app:compileDebugKotlin
> Task :app:compileDebugJavaWithJavac
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:dexBuilderDebug
> Task :app:mergeProjectDexDebug
> Task :app:packageDebug
> Task :app:createDebugApkListingFileRedirect UP-TO-DATE
> Task :app:assembleDebug
BUILD SUCCESSFUL in 3s
33 actionable tasks: 7 executed, 26 up-to-date
Build Analyzer results available
此外,您还可以看到 table 数据包 table 将使用 SQL(由 Room 在生成的 java 代码中生成)按照:-
_db.execSQL("CREATE TABLE IF NOT EXISTS `Packet` (`id` INTEGER NOT NULL, `userId` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `sessionId` TEXT NOT NULL, `timestamp` INTEGER, `duration` INTEGER, `protocol` TEXT, `requestMethod` TEXT, `requestUrl` TEXT, `requestHeaders` TEXT, `requestBody` TEXT, `requestSize` INTEGER, `responseCode` INTEGER, `responseHeaders` TEXT, `responseBody` TEXT, `responseSize` INTEGER, PRIMARY KEY(`id`))");
我正在用 Kotlin 编写 android 应用程序。尝试使用 room 将数据保存到本地存储。 但是我有一个错误:“无法弄清楚如何将这个字段保存到数据库中。你可以考虑为它添加一个类型转换器”。
我尝试根据文档并借助 Stack Overflow 上的示例将转换器转换为字符串。但我仍然有同样的错误。请告诉我如何避免它。 这是我的 class 我形成结构的地方:
data class Request(
val method: String?,
val url: String?,
val headers: Map<String, List<String>>?,
val body: String,
val size: Int,
)
data class Response(
val code: Int?,
val headers: Map<String, List<String>>?,
val body: String?,
val size: Int?,
)
@Entity
data class Packet(
@PrimaryKey val id: Int,
val userId: String,
val deviceId: String,
val sessionId: String,
val timestamp: Long?,
val duration: Int?,
val protocol: String?,
@Embedded val request: Request?,
@Embedded val response: Response?,
)
这就是我保存数据的方式
@Database(
version = 1,
entities = [Packet::class]
)
abstract class NetworkDatabase : RoomDatabase() {
abstract fun packetDao(): PacketDao
}
SQLite(room 是包装器的关系数据库)仅限于 table(@Entity 注释 class)具有可以包含单个值的列仅限于一小组类型(TEXT(String) INTEGER(Int,Long,....) REAL(Float,Double,....) BLOB(ByteArray) 和 NUMERIC(Room 不可用))
As Such youMap<String, List<String>>
无法直接存储。您需要将其转换为单个值或更正确,在列表的情况下,在数据库术语中另一个 table。但是,通常会放弃使用 table 以更方便地转换为单个值,通常是将 object(s) 表示为字符串的 JSON 字符串。
Room 通过使用两个注释 @TypeConverter
和 @TypeConverters
- 前者先于执行从 object 到受支持值的转换的函数,并且始终是执行相反操作的补充函数。
- 第二个定义包含函数及其作用域的 classes。
所以你需要有带@TypeConvert 注释的函数和一个带 suitable 范围的@TypeConverters(在@Database 级别给出了最广泛的范围)。
当您在数据包中嵌入请求和响应时 classes (table)。您还会遇到列命名问题,因为 headers、body 和大小 variables/fields 具有相同的名称。
此外,如果使用 JSON 字符串进行最方便的转换,List、Maps 和 Arrays 处理起来会有点困难。控股class可以简化事情。
1).由于 JSON 将用于从 object 转换为 JSON 字符串,因此您应该为 com.google.code.gson 添加依赖项,例如implementation 'com.google.code.gson:gson:2.9.0'
到您的构建 gradle(模块)。
- 还有其他选择
2).修改 classes 以便 variable/field 名称不会与列名称重复,并另外为地图引入一个控股 class (一个适合 Response 和 Request classes) .所以 classes 可能是 :-
/* Holding Class */
data class Mapping (
val header: Map<String, List<String>>
)
/* Note changed column names */
data class Request(
val requestMethod: String?,
val requestUrl: String?,
val requestHeaders: Mapping?,
val requestBody: String,
val requestSize: Int
)
/* Note changed column names */
data class Response(
val responseCode: Int?,
val responseHeaders: Mapping?,
val responseBody: String?,
val responseSize: Int?
)
@Entity
data class Packet(
@PrimaryKey val id: Int,
val userId: String,
val deviceId: String,
val sessionId: String,
val timestamp: Long?,
val duration: Int?,
val protocol: String?,
@Embedded val request: Request?,
@Embedded val response: Response?
)
3).为 TypeConverter 函数添加一个 class,将持有(映射)class to/from 转换为 object 的 JSON 字符串表示,例如:-
class RoomTypeConverters {
@TypeConverter
fun fromMappingToJSONString(mapping: Mapping): String {
return Gson().toJson(mapping)
}
@TypeConverter
fun fromJSONStringToMapping(jsonString: String): Mapping {
return Gson().fromJson(jsonString,Mapping::class.java)
}
}
4).添加具有 suitable 范围的 @TypeConverters 注释,完整范围在 @Database 级别,因此注释为 class 的 @Database 可以是 :-
@TypeConverters(value = [RoomTypeConverters::class]) //<<<<<<<<<< defines the classes that include the @TypeConverter annotated functions
@Database(entities = [Packet::class], version = 1, exportSchema = false)
abstract class TheDatabase: RoomDatabase() {
....
}
使用上面的方法构建成功,例如
Executing tasks: [:app:assembleDebug] in project E:\AndroidStudioApps\SO72128161KotlinRoomTypeConverters
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs NO-SOURCE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:kaptGenerateStubsDebugKotlin
> Task :app:kaptDebugKotlin
> Task :app:compileDebugKotlin
> Task :app:compileDebugJavaWithJavac
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:dexBuilderDebug
> Task :app:mergeProjectDexDebug
> Task :app:packageDebug
> Task :app:createDebugApkListingFileRedirect UP-TO-DATE
> Task :app:assembleDebug
BUILD SUCCESSFUL in 3s
33 actionable tasks: 7 executed, 26 up-to-date
Build Analyzer results available
此外,您还可以看到 table 数据包 table 将使用 SQL(由 Room 在生成的 java 代码中生成)按照:-
_db.execSQL("CREATE TABLE IF NOT EXISTS `Packet` (`id` INTEGER NOT NULL, `userId` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `sessionId` TEXT NOT NULL, `timestamp` INTEGER, `duration` INTEGER, `protocol` TEXT, `requestMethod` TEXT, `requestUrl` TEXT, `requestHeaders` TEXT, `requestBody` TEXT, `requestSize` INTEGER, `responseCode` INTEGER, `responseHeaders` TEXT, `responseBody` TEXT, `responseSize` INTEGER, PRIMARY KEY(`id`))");