При использовании Room всякий раз, когда новые таблицы добавляются в вашу базу данных, вы должны создать ее при переносе.К сожалению, в Room нет такого метода для создания таблицы, просто давая имя класса.Что-то ниже необходимо иметь
room.createTable(User::class)
Подобный метод существует, например, в OrmLite
TableUtils.createTable(connectionSource, User::class.java)
Необходимость заключается в сложности создания таблиц с помощью простого SQLite запрос.В настоящее время вы можете написать в своем migrate
сценарии create SQLite
db.execSQL("CREATE TABLE IF NOT EXIST `User` (uid INTEGER NON NULL, PRYMARY KEY (`uid`))")
В вышеприведенном методе нет проблем, но он становится сложным и длинным SQLite скрипт, если у вас есть, например, 50 полей.Очевидно, что вы не пишете это самостоятельно, и есть два способа получить Create Script , автоматически сгенерированный для вас Room, чтобы вы просто скопировали прошлое.
- После сборки приложения будет сгенерировано
AppDatabase_Impl
, в котором будут все необходимые создания таблиц.Вы можете получить запрос оттуда - Вы включите
exportSchema = true
в свою аннотацию @Database
, и она создаст versionNumber.json
схему базы данных Room в вашей папке схем.Вы можете получить сценарий создания оттуда.
Но оба вышеуказанных метода потребуют от вас запустить приложение без какой-либо надлежащей миграции (поскольку вы не знаете правильный запрос), и оно определенно авария .И после этого у вас есть правильный запрос, который вы можете включить в свой метод миграции.Я думаю, что это не "профессиональный" способ сделать это.Кроме того, даже после того, как вы получите длинный запрос 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()
}
Но проблема в том, что Аннотации комнат помечены
@Retention(RetentionPolicy.CLASS)
, к которым можно получить доступ только во время компиляции.Они не доступны во время выполнения.Так что все мои findAnnotation
методы вернут null
.Я думал о создании во время компиляции, но не мог придумать, как это сделать.
Итак, мой вопрос был: есть ли способ генерировать скрипты CREATE во время компиляции и если да, то как это сделать?
Помимо упомянутого мной способа решения, есть ли другой способ создания таблиц, который не включает в себя первые два метода вставки копий?
И, кстати, я не рассматриваю fallbackToDestructiveMigration
,Я имею в виду, кто бы хотел, чтобы их пользователи потеряли все данные?