26

green dao を使用したスキーマのアップグレード/移行に関する別の質問を見ました (こちら)

その回答には、スキーマのアップグレードを行うときに使用する適切なパターンのリンクがたくさんありますが、データを適切に移行するために実際にデータに対して行うことの例はなく、何かを見つけるのに苦労しています.

私の場合、移行は信じられないほど簡単です。既存のデータを変換したくありません。スキーマに新しいテーブルをいくつか追加する必要があるだけです。これはかなり一般的な状況だと思います。

ユーザーが既に保存したデータを削除せずに、スキーマに新しいテーブルを追加する最も簡単な方法は何ですか? 具体的な例をいただければ幸いです。

greenDao が DevOpenHelper に似たクラスを提供し、既存のテーブル/データを最初に削除せずに、スキーマに以前は存在しなかった新しいテーブル/列を追加するだけであれば素晴らしいことです。

4

4 に答える 4

9

以前のユーザーがどこから来たかに関係なく、更新を自動的に処理するために、少し異なるアプローチを行いました。最初に、SQLDatabase でメソッド onUpgrade を実装するクラスを作成しました

public abstract class AbstractMigratorHelper {

public abstract void onUpgrade(SQLiteDatabase db);
}

このクラスから、後で宣言するすべての移行ヘルパーが継承されます

私はそれらの1つの例を書きます

public class DBMigrationHelper5 extends AbstractMigratorHelper {

/* Upgrade from DB schema x to schema x+1 */


public void onUpgrade(SQLiteDatabase db) {
    //Example sql statement
    db.execSQL("ALTER TABLE user ADD COLUMN USERNAME TEXT");
 }
}

この後、アップグレード時に実際に呼び出されるクラスにロジックを実装する必要があります。ここでは、次のようなカスタムの DevOpenHelper の以前の DevOpenHelper を削除する必要があります。

public static class UpgradeHelper extends OpenHelper {

    public UpgradeHelper(Context context, String name, CursorFactory factory) {
        super(context, name, factory);
    }

    /**
     * Here is where the calls to upgrade are executed
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        /* i represent the version where the user is now and the class named with this number implies that is upgrading from i to i++ schema */
        for (int i = oldVersion; i < newVersion; i++) {
            try {
                /* New instance of the class that migrates from i version to i++ version named DBMigratorHelper{version that the db has on this moment} */
                AbstractMigratorHelper migratorHelper = (AbstractMigratorHelper) Class.forName("com.nameofyourpackage.persistence.MigrationHelpers.DBMigrationHelper" + i).newInstance();

                if (migratorHelper != null) {

                    /* Upgrade de db */
                    migratorHelper.onUpgrade(db);
                }

            } catch (ClassNotFoundException | ClassCastException | IllegalAccessException | InstantiationException e) {

                Log.e(TAG, "Could not migrate from schema from schema: " + i + " to " + i++);
                /* If something fail prevent the DB to be updated to future version if the previous version has not been upgraded successfully */
                break;
            }


        }
    }
}

そのため、移行ヘルパーの名前を慎重に付ける場合 (つまり、MigrationHelper5 はスキーマ 5 からスキーマ 6 への移行を行います)、このロジックを実装し、すべての MigratorHelper クラスで、実装する必要があるすべての SQL コードを使用して execSQL 呼び出しを実装するだけです。

最後にもう 1 つ注意点があります。proguard を使用している場合、コードを難読化するときにクラス名が変更されるため、クラスごとに名前を検索するメソッドが機能しない可能性があります。Proguard 構成ファイル (proguard-rules.pro) に例外を追加して、AbstractMigratorHelper から拡張されたクラスを除外することを検討してください。

# Avoid errors when upgrading database migrators

-keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper
于 2014-09-23T09:16:44.537 に答える
5

少し違うやり方でやっています。

新しい @DatabaseTable クラスと @DatabaseFields を既存の @DatabaseTable クラスに追加し、DatabaseConfigUtil を実行します。

次に、DatabaseUpgrader クラスに新しいメソッドを追加し、DatabaseHelper を変更して、DATABASE_VERSION 値と onUpdate メソッドを変更します。

public class DatabaseHelper extends OrmLiteSqliteOpenHelper {

    private static final int DATABASE_VERSION = 3;

    @Override
    public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {

        if (newVersion > oldVersion) {
            switch (oldVersion) {
                case 1:
                    DatabaseUpdater.from1to2(connectionSource);
                    DatabaseUpdater.from2to3(connectionSource);
                    break;

                case 2:
                    DatabaseUpdater.from2to3(connectionSource);
                    break;

                default:
                    onCreate(db);
            }
        }
    }

    public static DatabaseHelper getInstance() {

        return DatabaseHelper.mHelper;
    }

    public static void setInstance(Context context) {

        DatabaseHelper.mHelper = new DatabaseHelper(context);
    }

    …
}

そして DatabaseUpdater クラスで

public class DatabaseUpdater {

    private static final String TAG = "DatabaseHelper";

    public static void from1to2(ConnectionSource connectionSource) {

        try {
            DatabaseHelper helper = DatabaseHelper.getInstance();

            //Example add a table
            TableUtils.createTable(connectionSource, AnotherEntity.class);


        } catch (SQLException e) {
            Log.e(TAG, "Error upgrading database to v2: ", e);
        } catch (java.sql.SQLException e) {
            e.printStackTrace();
        }

    }

    public static void from2to3(ConnectionSource connectionSource) {

        try {
            DatabaseHelper helper = DatabaseHelper.getInstance();

            //Example add a field to a table
            RuntimeExceptionDao<MyEntity, Integer> myDao = helper.getMyDao();
            diaryDao.executeRaw("ALTER TABLE myEntity ADD firstNewField");
            diaryDao.executeRaw("ALTER TABLE myEntity ADD anotherNewField");


        } catch (SQLException e) {
            Log.e(TAG, "Error upgrading database to v3: ", e);
        }

    }
}
于 2013-08-16T06:56:18.650 に答える