如果仅添加新表,则迁移会议室数据库 [英] Room database migration if only new table is added
问题描述
让我们假设我有一个简单的Room数据库:
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
现在,我要添加一个新实体:Pet
并将版本增加到2:
@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
当然,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`))");
}
};
但是我发现手动操作很不方便. 有没有办法告诉Room:我没有触摸任何现有的表,所以数据是安全的.请为我创建迁移吗?
Room 确实没有拥有良好的迁移系统,至少直到2.1.0-alpha03
为止.>
因此,在我们拥有更好的迁移系统之前,有一些变通办法可以在会议室中轻松进行迁移.
因为没有@Database(createNewTables = true)
或MigrationSystem.createTable(User::class)
这样的方法,应该有一个或另一个方法,所以唯一可能的方法是运行
CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
. 为了获得 SQL 脚本,您有4种方法 基本上,您必须编写与Room生成的脚本匹配的上述脚本.这种方式是可行的,是不可行的. (考虑您有50个字段) 如果在 确保已在应用模块的 运行或构建项目时,您将获得一个JSON文件 因此,您可以将上述 如果您不想导出架构,则仍然可以通过运行或构建将生成 在 您可能会猜到,Room会在编译时间内并使用您添加的注释处理功能生成上述所有 这意味着您也可以执行相同操作,并创建自己的注释处理库,该库将为您生成所有必要的创建查询. 这个想法是为
然后,您可以将其用作 我为自己创建了一个这样的库,您可以检出它,甚至可以在您的项目中使用它.请注意,我制作的库并不完整,仅能满足我对表创建的要求. 希望它有用. 在撰写此答案时,会议室版本为 预计在 不幸的是,我们仍然缺乏更好的迁移系统. Let't assume, I have a simple Room database: Now, I'm adding a new entity: Of course, Room throws an exception: Assuming, I haven't changed However I find it inconvenient to do it manually.
Is there a way to tell Room: I'm not touching any of the existing table, so data is safe. Please create migration for me? Room does NOT have a good Migration System, at least not until So, until we have better Migration System, there are some workarounds to have easy Migrations in the Room. As there is no such method as inside your In order to get above SQL script, you have 4 ways Basically, you have to write the above script that will match the script that Room generates. This way is possible, not feasible. (Consider you have 50 fields) If you include Make sure that you have included below lines in When you run or build the project you will get a JSON file So, you can include the above If you don't want to export schema you can still get the query by running or building the project which will generate Within As you might guess, Room generates all of the above mentioned That means you can also do the same and make your own annotation processing library that generates all the necessary create queries for you. The idea is to make an annotation processing library for Room annotations of
Then, you can use it as I made such a library for myself which you can check out, and even use it in your project. Note that the library that I made is not full and it just fulfills my requirements for table creation. RoomExtension for better Migration Application that uses RoomExtension Hope it was useful. By the time of writing this answer, room version was It is expected to have better Migration System in Unfortunately, we still lack better Migration System. 这篇关于如果仅添加新表,则迁移会议室数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!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`))")
}
}
1.自己写
2.导出架构
@Database
批注中包含exportSchema = true
,Room将在项目文件夹的/schemas中生成数据库架构.用法是@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
build.grade
中包括以下行kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
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
},
createSql
包含在migrate
方法中. 3.从AppDatabase_Impl获取查询
AppDatabase_Impl.java
文件的项目来获取查询.并在指定文件内. @Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
createAllTables
方法中,将存在所有实体的创建脚本.您可以获取它并将其包含在您的migrate
方法中. 4.注释处理.
schema
和AppDatabase_Impl
文件.kapt "androidx.room:room-compiler:$room_version"
@Entity
和@Database
的房间注释创建一个注释处理库.以一个用@Entity
注释的类为例.这些是您必须遵循的步骤
StringBuilder
并附加如果不存在则创建表" class.simplename
或通过@Entity
的tableName
字段获取表名.将其添加到您的StringBuilder
@ColumnInfo
注释获取字段的名称,类型和可空性.
对于每个字段,您都必须在StringBuilder
中添加列的id INTEGER NOT NULL
样式.@PrimaryKey
ForeignKey
和Indices
(如果存在).public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
更新
2.1.0-alpha03
,当我向开发人员发送电子邮件时,得到了回复
2.2.0
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
Pet
and bumping version to 2:@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
java.lang.IllegalStateException: A migration from 1 to 2 is necessary.
User
class (so all data is safe), I have to provide migration which just creates a new table. So, I'm looking into classes generated by Room, searching for generated query to create my new table, copying it and pasting into migration: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`))");
}
};
2.1.0-alpha03
.@Database(createNewTables = true)
or MigrationSystem.createTable(User::class)
, which there should be one or other, the only possible way is running CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
migrate
method. 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`))")
}
}
1. Write by yourself
2. Export Schema
exportSchema = true
inside your @Database
annotation, Room will generate database schema within /schemas of your project folder. The usage is@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
build.grade
of your app modulekapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
2.json
, which has all the queries within your Room database. "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
},
createSql
within you migrate
method.3. Get query from AppDatabase_Impl
AppDatabase_Impl.java
file. and within the specified file you can have. @Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
createAllTables
method, there will be the create scripts of all the entities. You can get it and include in within you migrate
method.4. Annotation Processing.
schema
, and AppDatabase_Impl
files within compilation time and with Annotation Processing which you add withkapt "androidx.room:room-compiler:$room_version"
@Entity
and @Database
. Take a class that is annotated with @Entity
for example. These are the steps you will have to follow
StringBuilder
and append "CREATE TABLE IF NOT EXISTS "class.simplename
or by tableName
field of @Entity
. Add it to your StringBuilder
@ColumnInfo
annotation.
For every field, you have to add id INTEGER NOT NULL
style of a column to your StringBuilder
.@PrimaryKey
ForeignKey
and Indices
if exists.public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
UPDATE
2.1.0-alpha03
and when I emailed developers I got a response of
2.2.0