새 테이블 만 추가 된 경우 Room 데이터베이스 마이그레이션
간단한 Room 데이터베이스가 있다고 가정하겠습니다.
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
이제 새 엔티티를 추가하고 Pet2에 버전을 범핑합니다.
@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에 알리는 방법이 있습니까? 기존 테이블을 건드리지 않기 때문에 데이터가 안전합니다. 나를 위해 마이그레이션을 만드시겠습니까?
방은 않습니다 하지 적어도되지 때까지, 좋은 마이그레이션 시스템을 가지고 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`))
당신의 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`))")
}
}
위의 SQL 스크립트 를 얻으려면 4 가지 방법이 있습니다.
1. 혼자서 쓰기
기본적으로 Room에서 생성하는 스크립트와 일치하는 위의 스크립트를 작성해야합니다. 이 방법은 가능하지만 불가능합니다. (50 개의 필드가 있다고 가정)
2. 스키마 내보내기
주석 exportSchema = true안에 포함하면 @DatabaseRoom은 프로젝트 폴더의 / schemas 내에 데이터베이스 스키마를 생성합니다. 사용법은
@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
build.grade앱 모듈의 아래 줄을 포함했는지 확인하십시오.
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
프로젝트를 실행하거나 빌드하면 2.jsonRoom 데이터베이스 내에 모든 쿼리가 포함 된 JSON 파일 이 생성됩니다.
"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. 주석 처리.
As you might guess, Room generates all of the above mentioned schema, and AppDatabase_Impl files within compilation time and with Annotation Processing which you add with
kapt "androidx.room:room-compiler:$room_version"
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 @Entity and @Database. Take a class that is annotated with @Entity for example. These are the steps you will have to follow
- Make a new
StringBuilderand append "CREATE TABLE IF NOT EXISTS " - Get the table name either from
class.simplenameor bytableNamefield of@Entity. Add it to yourStringBuilder - Then for each field of your class create columns of SQL. Take the name, type, nullability of the field either by the field itself or by
@ColumnInfoannotation. For every field, you have to addid INTEGER NOT NULLstyle of a column to yourStringBuilder. - Add primary keys by
@PrimaryKey - Add
ForeignKeyandIndicesif exists. - After finishing convert it to string and save it in some new class that you want to use. For example, save it like below
public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
Then, you can use it as
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
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.
Sorry, Room doesn't support auto-creation of tables without data loss.
It is mandatory to write the migration. Otherwise, it'll erase all the data and create the new table structure.
You can do this way-
@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
public abstract Dao getPetDao();
}
Remaining will be same as you have mentioned above-
db = Room.databaseBuilder(this, AppDatabase::class.java, "your_db")
.addMigrations(MIGRATION_1_2).build()
Reference - For more
You can add the following gradle command to your defaultConfig in your app.gradle:
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
When you run this it will compile a list of table names with their relevant CREATE TABLE statements from which you can just copy and paste into your migration objects. You might have to change the table names.
For example this is from my generated schema:
"tableName": "assets",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `base` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`asset_id`))"
And so I copy paste the createSql statement and change the '${TABLE_NAME}' to 'assets' the table name, and voila auto generated Room create statements.
Maybe in this case(if you've only created new table without changing others) you can do this not creating any migrations at all?
In this case, you don't need to do a migration, you can call .fallbackToDestructiveMigration() when you are creating database instance.
Example:
instance = Room.databaseBuilder(context, AppDatabase.class, "database name").fallbackToDestructiveMigration().build();
And don't forget to change database version.
참고URL : https://stackoverflow.com/questions/48399852/room-database-migration-if-only-new-table-is-added
'Program Club' 카테고리의 다른 글
| WPF / XAML의 오픈 소스 대안은 무엇입니까? (0) | 2020.11.15 |
|---|---|
| 컬렉션에서 임의의 하위 집합을 선택하는 가장 좋은 방법은 무엇입니까? (0) | 2020.11.15 |
| Linux OS 용 Github GUI 클라이언트가 있습니까? (0) | 2020.11.15 |
| System.Web.HttpUtility.UrlEncode / UrlDecode ASP.NET 5 대체 (0) | 2020.11.14 |
| 2016.2로 업데이트 한 후 Pycharm import RuntimeWarning (0) | 2020.11.14 |