Pio*_*ski 73 java android database-migration android-room
不要假设,我有一个简单的房间数据库:
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
Run Code Online (Sandbox Code Playgroud)
现在,我正在添加一个新实体:Pet
并将版本提升为2:
@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
Run Code Online (Sandbox Code Playgroud)
当然,Room会抛出异常: java.lang.IllegalStateException: A migration from 1 to 2 is necessary.
假设,我没有更改User
类(因此所有数据都是安全的),我必须提供只创建新表的迁移.所以,我正在调查Room生成的类,搜索生成的查询以创建我的新表,复制它并粘贴到迁移中:
final Migration MIGRATION_1_2 =
new Migration(1, 2) {
@Override
public void migrate(@NonNull final SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `Pet` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))");
}
};
Run Code Online (Sandbox Code Playgroud)
但是我觉得手动操作不方便.有没有办法告诉Room:我没有触及任何现有的表,所以数据是安全的.请为我创建迁移?
mus*_*off 40
房确实不具备良好的迁移系统,至少直到2.1.0-alpha03
.
预计将有更好的移民系统
2.2.0
因此,在我们拥有更好的迁移系统之前,有一些解决方法可以在房间内轻松迁移.
由于没有这样的方法,@Database(createNewTables = true)
或者MigrationSystem.createTable(User::class)
应该有一个或另一个方法,唯一可行的方法是运行
CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
Run Code Online (Sandbox Code Playgroud)
在你的migrate
方法里面.
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))")
}
}
Run Code Online (Sandbox Code Playgroud)
为了获得上述SQL脚本,您有4种方法
基本上,您必须编写上述脚本,该脚本将与Room生成的脚本相匹配.这种方式是可行的,不可行.(考虑你有50个领域)
如果exportSchema = true
在@Database
注释中包含,则Room将在项目文件夹的/ schemas中生成数据库模式.用法是
@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
Run Code Online (Sandbox Code Playgroud)
确保build.grade
您的应用模块中包含以下行
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
Run Code Online (Sandbox Code Playgroud)
当您运行或构建项目时,您将获得一个JSON文件2.json
,该文件包含Room数据库中的所有查询.
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "325bd539353db508c5248423a1c88c03",
"entities": [
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
Run Code Online (Sandbox Code Playgroud)
因此,您可以createSql
在您的migrate
方法中包含上述内容.
如果您不想导出模式,您仍然可以通过运行或构建将生成AppDatabase_Impl.java
文件的项目来获取查询.并且在指定的文件中,您可以拥有.
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
Run Code Online (Sandbox Code Playgroud)
在createAllTables
方法中,将存在所有实体的创建脚本.你可以得到它并包含在你的migrate
方法中.
正如您可能猜到的那样,Room会生成上述所有内容schema
,以及AppDatabase_Impl
编译时的文件以及您添加的注释处理
kapt "androidx.room:room-compiler:$room_version"
Run Code Online (Sandbox Code Playgroud)
这意味着您也可以执行相同操作并创建自己的注释处理库,为您生成所有必需的创建查询.
我们的想法是为@Entity
和的房间注释制作一个注释处理库@Database
.拿一个用@Entity
例如注释的类.这些是您必须遵循的步骤
StringBuilder
并附加"CREATE TABLE IF NOT NOT EXISTS"class.simplename
或从tableName
字段获取表名@Entity
.把它添加到你的StringBuilder
@ColumnInfo
注释获取字段的名称,类型,可为空性.对于每个字段,您必须为您的字段添加id INTEGER NOT NULL
列样式StringBuilder
.@PrimaryKey
ForeignKey
,Indices
如果存在.2.1.0-alpha03
public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以将其用作
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
Run Code Online (Sandbox Code Playgroud)
我为自己制作了这样一个图书馆,你可以查看,甚至在你的项目中使用它.请注意,我创建的库不完整,它只是满足我对表创建的要求.
希望它有用.
归档时间: |
|
查看次数: |
12242 次 |
最近记录: |