在房间中创建表格的方法[重复]

Posted

技术标签:

【中文标题】在房间中创建表格的方法[重复]【英文标题】:Method to create tables in Room [duplicate] 【发布时间】:2019-05-16 20:24:07 【问题描述】:

使用 Room 时,只要将新表添加到数据库中,您就必须在迁移中创建它。不幸的是,Room 没有这样的方法来通过给出类名来创建表。下面的东西是必要的

room.createTable(User::class)

类似的方法存在于例如OrmLite

TableUtils.createTable(connectionSource, User::class.java)

必要性来自于使用简单的SQLite 查询创建表的复杂性。目前,您可以在 migrate 中编写您的创建 SQLite 脚本

db.execSQL("CREATE TABLE IF NOT EXIST `User` (uid INTEGER NON NULL, PRYMARY KEY (`uid`))")

上面的方法没有问题,但是如果你有 50 个字段,它会变得复杂而冗长的 SQLite 脚本。显然不是你自己写的,有两种方法可以让Room为你自动生成的Create Script,让你直接复制过去。

    在构建应用程序后,将生成AppDatabase_Impl,它会创建所有必要的表。您可以从那里获取查询 您将exportSchema = true 包含在您的@Database 注释中,它将在您的架构文件夹中创建Room 数据库的versionNumber.json 架构。您可以从那里获取创建脚本。

但是,以上两种方法都要求您在没有任何适当迁移的情况下运行应用程序(因为您不知道正确的查询),并且它肯定会崩溃。之后,您就有了可以包含在迁移方法中的正确查询。我认为这不是“专业”的做法。另外,即使您获得了长 SQLite 查询,它也不是 PR 友好的,而且长 SQLite 查询不仅仅是一个好习惯易于调试。

所以,我想在迁移时以面向对象的方式创建表。显然,我能想到的唯一方法是使用模型数据类并根据模型的每个字段生成查询。应该是这样的

fun createTable(db: SupportSQLiteDatabase, clazz: KClass<*>) 
    val fields = extractColumns(clazz)
    val primaryKeys = fields
            .filter  it.primaryKey 
            .map  it.name 

    val createQuery = "CREATE TABLE IF NOT EXISTS `$clazz.simpleName` (" +
            fields.joinToString(", ")  "`$it.name` $it.type $it.nonNull"  +
            ", PRIMARY KEY (" + primaryKeys.joinToString(",")  "`$it`"  +
            "))"
    db.execSQL(createQuery)


fun extractColumns(clazz: KClass<*>): Array<Column>
    val columns = ArrayList<Column>()
    for (field in clazz.declaredMemberProperties)
        val name = field.findAnnotation<ColumnInfo>()?.name ?: field.name
        val type = getSqlType(field.returnType)
        val nonNull = if (field.returnType.isMarkedNullable) "" else "NON NULL"
        val primaryKey = field.findAnnotation<PrimaryKey>() != null
        columns.add(Column(name, type, nonNull, primaryKey))
    
    return columns.toTypedArray()

但问题是 Room Annotations 都用 @Retention(RetentionPolicy.CLASS) 进行了注释,只能在编译时访问。它们在运行时不可用。所以我所有的findAnnotation 方法都将返回null。我想在编译时进行创建,但想不出怎么做。

那么,我的问题是有什么方法可以在编译期间生成 CREATE 脚本,如果可以,该怎么做?

除了我提到的解决方法之外,还有其他不涉及复制粘贴的前两种方法的创建表的方法吗?

顺便说一句,我不考虑fallbackToDestructiveMigration。我的意思是,谁会希望他们的用户丢失所有数据?

【问题讨论】:

能否提供代码示例?我使用房间 + kotlin。这是代码示例 @Database(entities = [ProductOffer::class], version = 1) @TypeConverters(Converters::class) 抽象类 AppDatabase : RoomDatabase() abstract fun productOfferDao(): ProductOfferDao 。 Room 通过迁移自动生成实现。 代码示例是什么意思?如果您的意思是我如何创建AppDatabase,那与我提出的问题有什么关系?我可以提供,但您也可以在 official documentation 找到 你所说的Room automatically generates implementation with migrations是什么意思 您为我提供了有用的信息来获取带有 exportSchema 选项的 CREATE TABLE 查询。谢谢你:)顺便说一句,我同意你的看法,这种方法不专业。 我已经提供了有关创建表的更多信息here 【参考方案1】:

截至Room 的当前更新,实际上有一种方法可以使用Annotation Processing 创建SQL 查询。使用注解处理,您必须编写小型库,在构建时为您生成 Room 查询。

创建Annotation Processing Library 并不简单,这里是相关问题。

Room database migration if only new table is added

【讨论】:

以上是关于在房间中创建表格的方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 X++ 在 Excel 中创建多个工作表

如何在mysql中创建具有旧数据库中一些表的新数据库[重复]

如何在 Ejabberd 中创建非匿名房间 [关闭]

在 FUNCTION 中创建临时表 [重复]

如何在 SQL Server 2008 中创建具有新名称的重复表

如何使用 WEB SDK 在 QuickBlox 中创建房间