如何扩展Room数据库的@TypeConverter或者是否需要扩展?

问题描述 投票:0回答:1

我有一个数据类:

@Parcelize
data class Task(
    var task: String,
    var done: Boolean = false
) : Parcelable

以及我的 Room 数据库的相应类型转换器:

object Converters {

    ...

    @TypeConverter
    fun tasksToJson(list: List<Task>): String {
        val objects = list.map { item ->
            val jsonObject = JSONObject()
            jsonObject.put("task", item.task)
            jsonObject.put("done", item.done)
        }
        return JSONArray(objects).toString()
    }

    @TypeConverter
    fun jsonToTasks(json: String): List<Task> {
        val iterable = JSONArray(json).iterable<JSONObject>()
        return iterable.map { jsonObject ->
            Task(jsonObject.getString("task"), jsonObject.getBoolean("done"))
        }
    }

    @Suppress("UNCHECKED_CAST")
    private fun <T> JSONArray.iterable(): Iterable<T> {
        return Iterable {
            object : Iterator<T> {
                var nextIndex = 0

                override fun next(): T {
                    val element = get(nextIndex)
                    nextIndex++
                    return element as T
                }

                override fun hasNext(): Boolean {
                    return nextIndex < length()
                }
            }
        }
    }
}

一切都很好,但我想扩展我的数据类,以便每个任务都有一个子任务。这就是我扩展数据类的方式:

@Parcelize
data class Task(
    var task: String,
    var done: Boolean = false,
    var subTasks: List<Task> = emptyList() // -> sub tasks based on the same data class
) : Parcelable

所以问题是,我是否也需要为子任务扩展类型转换器?如果是的话,我该如何完成?

android-room typeconverter
1个回答
0
投票

所以问题是,我是否也需要为子任务扩展类型转换器?如果是的话,我该如何完成?

答案可能是但这取决于相应的

@Entity
注释类

总而言之,如果Task,无论它是否包含子任务列表,都没有嵌入,那么 TypeConverter 应该足够了,因为

List<Task>
是存储/检索的 Task 对象的一部分(通过转换) TypeConverter 对)。

但是,如果Task嵌入了

@Embedded
注释,那么;在添加子任务列表之前,所有字段都是 Room 可以处理的类型,但在添加之后;这 子任务
List<Task>
字段/成员,因为它本身就成为一列,因此需要一个 TypeConverter 对。

更具体一点

@Entity
注释的类,如果
entities
注释的
@Database
参数中的实体之一确定表的列。

如果需要类型转换器的对象直接是类的字段/成员,那么该字段/成员本身就是一列。如果该字段/成员不是 Room 可以直接处理的类型,那么它将需要一对 TypeConverter 函数/方法将对象转换为 Room 可以处理的类型。

例如如果你有:-

@Entity
data class TheTable(
   @PrimaryKey
   val id: Long?=null,
   val something: String,
   val task: Task
}

然后

task
字段/成员相当于名为
task
的列,底层值是一个对象,需要一个 TypeConverter 对来将 Task 对象转换为可存储的值或从可存储的值转换为在 SQLite 数据库中。

数据库中的表将使用

CREATE TABLE IF NOT EXISTS 
TheTable
 (
id
INTEGER,
something
TEXT NOT NULL,
task
 TEXT NOT NULL, PRIMARY KEY(
id
))
创建。即列将是:-

  1. id id(整数类型(Long Int Byte,甚至布尔值)由 Room 处理,并给定 SQLite 类型 INTEGER)

  2. 某物(字符串类型,相当于 SQLite 类型 TEXT)

  3. 任务(因为任务是任务的一种类型,所以 Room 不知道要做什么!但是,由于提供了返回 String 的 TypeConverter,因此分配了 TEXT 的 SQLite 类型)。

    • 类型转换器,为了简单地生成答案而没有用(数据方面)
      @TypeConverter fun cnvTaskToString(task: Task): String = ""
      (它将任务转换为“”)

但是,如果您有:-

@Entity
data class TheTable(
   @PrimaryKey
   val id: Long?=null,
   val something: String,
   @Embedded
   val task: Task
}

然后将使用

CREATE TABLE IF NOT EXISTS 
TheTable
 (
id
INTEGER,
something
TEXT NOT NULL,
task
TEXT NOT NULL,
done
 INTEGER NOT NULL, PRIMARY KEY(
id
))
创建表格,即列:-

  1. id(整数类型(Long Int Byte,甚至是布尔值)由 Room 处理,并赋予 SQLite INTEGER 类型)
  2. 某物(字符串类型,相当于 SQLite 类型 TEXT)
  3. 任务(因为任务对象的任务字段/成员是一个字符串,然后是文本)
  4. done(done 是一个布尔值,然后是 SQlite 类型 INTEGER)

即任务对象的字段已从任务对象复制。正如给定的示例中所示,字段/成员是可以处理的类型,然后不需要 TypeConverters。

但是,如果添加了列表字段,则如下所示:-

data class Task(
    var task: String,
    var done: Boolean = false,
    val subtasks: List<Task> = emptyList()
)
  • 注意默认添加了一个空列表,以简化原理演示的 TypeConverter(不需要列表)。

然后现有的 TypeConverter,如上所述(由于空列表默认值),可以应对。即 GSON 应该处理 JSON 字符串。 Room 关心的只是从相应的 Task 对象存储/检索字符串。

但是,如果任务是

@Embedded
,那么由于存在附加字段/成员,并且它不是 Room 可以处理的类型,因此作为列表的子任务对象/列将需要 TypeConverter,作为子任务,由于任务被嵌入。

© www.soinside.com 2019 - 2024. All rights reserved.