簡単な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にはNOTには優れた移行システムがあり、少なくとも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つの方法があります
基本的に、Roomが生成するスクリプトに一致する上記のスクリプトを作成する必要があります。この方法は可能ですが、不可能です。 (50のフィールドがあると考えてください)
exportSchema = true
アノテーション内に@Database
を含めると、Roomはプロジェクトフォルダーの/ schemas内にデータベーススキーマを生成します。使用法は
@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
アプリモジュールのbuild.grade
に以下の行が含まれていることを確認してください
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
プロジェクトを実行またはビルドすると、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
},
したがって、上記のcreateSql
をmigrate
メソッド内に含めることができます。
スキーマをエクスポートしたくない場合でも、AppDatabase_Impl.Java
ファイルを生成するプロジェクトを実行またはビルドすることでクエリを取得できます。指定したファイル内に含めることができます。
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
createAllTables
メソッド内には、すべてのエンティティの作成スクリプトがあります。取得して、migrate
メソッド内に含めることができます。
ご想像のとおり、Roomは上記のすべてのschema
およびAppDatabase_Impl
ファイルをコンパイル時間内に追加する注釈処理で生成します
kapt "androidx.room:room-compiler:$room_version"
つまり、同じことを行い、必要なすべての作成クエリを生成する独自の注釈処理ライブラリを作成することもできます。
アイデアは、@Entity
および@Database
のルーム注釈用の注釈処理ライブラリを作成することです。たとえば、@Entity
アノテーションが付けられたクラスを取り上げます。これらはあなたが従わなければならないステップです
StringBuilder
を作成し、「CREATE TABLE IF NOT EXISTS」を追加しますclass.simplename
または@Entity
のtableName
フィールドからテーブル名を取得します。 StringBuilder
に追加します@ColumnInfo
アノテーションのいずれかによって、フィールドの名前、タイプ、NULL値を許可します。すべてのフィールドについて、id INTEGER NOT NULL
スタイルの列をStringBuilder
に追加する必要があります。@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)
}
}
私は自分でチェックアウトできるライブラリを自分で作成し、プロジェクトで使用することさえできました。作成したライブラリがいっぱいではなく、テーブル作成の要件を満たしていることに注意してください。
役に立てば幸いです。
申し訳ありませんが、Roomはデータの損失なしにテーブルの自動作成をサポートしていません。
移行を記述することは必須です。それ以外の場合は、すべてのデータが消去され、新しいテーブル構造が作成されます。