web-dev-qa-db-ja.com

新しいテーブルのみが追加された場合のルームデータベースの移行

簡単な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つの方法があります

1.自分で書く

基本的に、Roomが生成するスクリプトに一致する上記のスクリプトを作成する必要があります。この方法は可能ですが、不可能です。 (50のフィールドがあると考えてください)

2.スキーマのエクスポート

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
          },

したがって、上記のcreateSqlmigrateメソッド内に含めることができます。

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.注釈処理。

ご想像のとおり、Roomは上記のすべてのschemaおよびAppDatabase_Implファイルをコンパイル時間内に追加する注釈処理で生成します

kapt "androidx.room:room-compiler:$room_version"

つまり、同じことを行い、必要なすべての作成クエリを生成する独自の注釈処理ライブラリを作成することもできます。

アイデアは、@Entityおよび@Databaseのルーム注釈用の注釈処理ライブラリを作成することです。たとえば、@Entityアノテーションが付けられたクラスを取り上げます。これらはあなたが従わなければならないステップです

  1. 新しいStringBuilderを作成し、「CREATE TABLE IF NOT EXISTS」を追加します
  2. class.simplenameまたは@EntitytableNameフィールドからテーブル名を取得します。 StringBuilderに追加します
  3. 次に、クラスの各フィールドに対してSQLの列を作成します。フィールド自体または@ColumnInfoアノテーションのいずれかによって、フィールドの名前、タイプ、NULL値を許可します。すべてのフィールドについて、id INTEGER NOT NULLスタイルの列をStringBuilderに追加する必要があります。
  4. @PrimaryKeyによる主キーの追加
  5. ForeignKeyおよびIndicesが存在する場合は追加します。
  6. 文字列への変換が完了したら、使用する新しいクラスに保存します。たとえば、次のように保存します
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)
    }
}

私は自分でチェックアウトできるライブラリを自分で作成し、プロジェクトで使用することさえできました。作成したライブラリがいっぱいではなく、テーブル作成の要件を満たしていることに注意してください。

移行を改善するためのRoomExtension

RoomExtensionを使用するアプリケーション

役に立てば幸いです。

32
musooff

申し訳ありませんが、Roomはデータの損失なしにテーブルの自動作成をサポートしていません。

移行を記述することは必須です。それ以外の場合は、すべてのデータが消去され、新しいテーブル構造が作成されます。