【问题标题】:Room database - get table name at runtime房间数据库 - 在运行时获取表名
【发布时间】:2022-03-14 07:07:22
【问题描述】:

假设我这样声明我的实体:

@Entity(tableName = "banana")
data class MyStuff(
@PrimaryKey val id: String
)

当 Room KAPT 执行时,它很神奇,@Entity 注释被剥离,因此它在运行时不再存在。

例如如果我写 MyStuff::class.annotations 它会返回空列表。

如果我使用了@Entity(tableName = "banana"),所以我的表名与我的类名不匹配,我如何查询 Room 数据库以找出给定的实体类型表示给定的表名?

更新

所以我找到了一个解决方法,虽然很可怕。

看来 Room 实际上并不知道 Entity 和 Table 之间的映射。 这些信息被编译到 DAO 的 BODY 中。

这也是为什么他们让你对你所有的表都使用 DAO,这非常冗长。

尽管如此,通过其他一些需求,我的项目中有以下注释:

@Target(AnnotationTarget.CLASS)
annotation class DaoType(val type: KClass<*>)

我还有一个从KClass&lt;*&gt;getDao 的方法。

我所有的 DAO 对象都包含一个自动生成的 deleteAll 方法,如下所示:

    @Delete
    fun deleteAll(vararg entities: MyStuff)

鉴于此,我可以像这样获得表名:

var tableName: String? = null

val daoType = (entityType.annotations.firstOrNull { it is DaoType } as? DaoType)
                ?.type
daoType?.let {
    val dao = getDao<Any>(it.java)
    dao?.let { d ->
        val statementFields: List<Field> =
            d::class.java.declaredFields.filter { f ->
                return@filter f.type.declaredMethods.firstOrNull { m -> m.name == "createQuery" } != null
            }
        for (field in statementFields) {
            field.isAccessible = true
            val fieldVal = field.get(d) ?: continue
            val method = field.type.declaredMethods.first { m -> m.name == "createQuery" }
            val query = method.invoke(fieldVal) as? String ?: continue
            if (query.startsWith("DELETE FROM ")) {
                var matchResult = "DELETE\\sFROM\\s`(.*?)`.*".toRegex().find(query)
                val table = matchResult?.groupValues?.lastOrNull()
                if (table != null) {
                    tableName = table
                }
            }
        }
    }
}

注意:我没有将此标记为可接受的答案,因为我对 Room 内部工作的依赖程度不满意。

不过,这至少现在有效。

【问题讨论】:

  • 只是想知道,为什么你想在运行时知道你的表名?
  • @SwapnilPadaya 我在数据库中有 100 多个表。我有共同的任务,例如“计算表中的行数”或“删除表中的所有行”等。我不想在 DAO 中重复这些方法。 (我们首先需要 DAO 已经够糟糕了)。
  • 你可以通过 DAO 传递一个参数(例如表名),并像 ContentResolver.query() 通过传递表名、选择投影......
  • Room 在后台使用 Sqlite,因此您应该能够使用此答案中的一种方法stackoverflow.com/questions/15383847/…
  • @IvanWooll 我当然可以得到表名。我如何知道该表对应于哪个 Kotlin 类?

标签: android kotlin android-room


【解决方案1】:

你可以使用类似的东西:-

@Entity(tableName = MyStuff.tableName)
data class MyStuff(
    @PrimaryKey  val id: String
) {
    companion object {
        const val tableName = "banana"
    }
}

【讨论】:

  • 是的,现在我需要这样做 100 多次......马年。
猜你喜欢
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多