在Room中创建表的方法
Method to create tables in Room
当新的 table 添加到您的数据库时使用 Room 时,您必须在迁移中创建它。不幸的是,Room 没有这样的方法来仅通过提供 class 名称来创建 table。以下内容是必备的
room.createTable(User::class)
例如 OrmLite
中存在类似的方法
TableUtils.createTable(connectionSource, User::class.java)
必要性来自创建 tables 的复杂性,只需简单的 SQLite 查询。目前,你可以做的是在你的 migrate
中编写你的创建 SQLite 脚本
db.execSQL("CREATE TABLE IF NOT EXIST `User` (uid INTEGER NON NULL, PRYMARY KEY (`uid`))")
上面的方法没有问题,但是如果你有例如 50 个字段,它会变得复杂和长 SQLite 脚本。显然不是你自己写的,有两种方法可以让Room自动为你生成Create Script,你直接copy过去即可。
- 构建应用程序后,
AppDatabase_Impl
将生成,它将包含所有必要的 table 创建内容。你可以从那里得到查询
- 您在
@Database
注释中包含 exportSchema = true
,它将在您的架构文件夹中创建 versionNumber.json
Room 数据库架构。您可以从那里获取创建脚本。
但是,上述两种方法都需要您 运行 应用程序而无需任何适当的迁移(因为您不知道正确的查询)并且它肯定会 崩溃 .之后,您就有了可以包含在迁移方法中的正确查询。我认为这不是 "professional" 的做法。此外,即使在您获得长 SQLite 查询之后,它也不是 PR 友好的,而且拥有长 SQLite 无法轻松调试的查询。
因此,我想采用面向对象的方式在迁移时创建 table。显然,我能想到的唯一方法是使用模型数据 class 并根据模型的每个字段生成查询。应该是这样的
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
方法都会 return null
。我想在编译时创建,但想不出怎么做。
所以,我的问题是有没有什么方法可以在编译期间生成 CREATE 脚本,如果可以,该怎么做?
除了我提到的解决方法之外,是否还有其他创建 tables 的方法不涉及前两种复制粘贴方法?
顺便说一下,我不考虑 fallbackToDestructiveMigration
。我的意思是,谁会希望他们的用户丢失所有数据?
截至 Room
的当前更新,实际上可以使用 Annotation Processing
创建 SQL 查询。使用注释处理,您必须编写小型库,在构建时为您生成 Room
查询。
创建 Annotation Processing Library
并不简单,这是相关问题。
当新的 table 添加到您的数据库时使用 Room 时,您必须在迁移中创建它。不幸的是,Room 没有这样的方法来仅通过提供 class 名称来创建 table。以下内容是必备的
room.createTable(User::class)
例如 OrmLite
中存在类似的方法TableUtils.createTable(connectionSource, User::class.java)
必要性来自创建 tables 的复杂性,只需简单的 SQLite 查询。目前,你可以做的是在你的 migrate
中编写你的创建 SQLite 脚本
db.execSQL("CREATE TABLE IF NOT EXIST `User` (uid INTEGER NON NULL, PRYMARY KEY (`uid`))")
上面的方法没有问题,但是如果你有例如 50 个字段,它会变得复杂和长 SQLite 脚本。显然不是你自己写的,有两种方法可以让Room自动为你生成Create Script,你直接copy过去即可。
- 构建应用程序后,
AppDatabase_Impl
将生成,它将包含所有必要的 table 创建内容。你可以从那里得到查询 - 您在
@Database
注释中包含exportSchema = true
,它将在您的架构文件夹中创建versionNumber.json
Room 数据库架构。您可以从那里获取创建脚本。
但是,上述两种方法都需要您 运行 应用程序而无需任何适当的迁移(因为您不知道正确的查询)并且它肯定会 崩溃 .之后,您就有了可以包含在迁移方法中的正确查询。我认为这不是 "professional" 的做法。此外,即使在您获得长 SQLite 查询之后,它也不是 PR 友好的,而且拥有长 SQLite 无法轻松调试的查询。
因此,我想采用面向对象的方式在迁移时创建 table。显然,我能想到的唯一方法是使用模型数据 class 并根据模型的每个字段生成查询。应该是这样的
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
方法都会 return null
。我想在编译时创建,但想不出怎么做。
所以,我的问题是有没有什么方法可以在编译期间生成 CREATE 脚本,如果可以,该怎么做?
除了我提到的解决方法之外,是否还有其他创建 tables 的方法不涉及前两种复制粘贴方法?
顺便说一下,我不考虑 fallbackToDestructiveMigration
。我的意思是,谁会希望他们的用户丢失所有数据?
截至 Room
的当前更新,实际上可以使用 Annotation Processing
创建 SQL 查询。使用注释处理,您必须编写小型库,在构建时为您生成 Room
查询。
创建 Annotation Processing Library
并不简单,这是相关问题。