Green daoを使用したスキーマのアップグレード/移行に関する別の質問を見ました( here )
スキーマのアップグレードを実行するときに使用する適切なパターンの答えはたくさんありますが、データを適切に移行するために実際にデータに対して行う例はなく、何も見つからないのです。
私の場合、私の移行は信じられないほど簡単です。既存のデータを変換したくないので、スキーマに新しいテーブルを追加するだけです。これはかなり一般的な状況だと思います。
ユーザーが既に保存したデータを削除せずに新しいテーブルをスキーマに追加する最も簡単な方法は何ですか?具体的な例をいただければ幸いです。
GreenDaoがDevOpenHelperに似たクラスを提供して、最初に既存のタブ/データを削除せずに、スキーマに以前は存在しなかった新しいテーブル/列を単純に追加するなら、それは素晴らしいでしょう。
私はついにこれを掘り下げる時間を持ち、古いテーブルのデータを保持しながら新しいテーブルを追加するのは非常に簡単であることに気付きました。
[〜#〜] disclaimer [〜#〜]:この実装は私のシナリオに固有のものであると私は理解していますが、Android ORMツール( greenDao)AndroidでSQLiteを処理するためだけに使用します。これは、最初から独自のテーブル作成クエリを作成したことがある人にはよくあることですが、AndroidでSQLite DBを使用することから逃れられた人にとって、この例は役立つと思います。
ANSWER: DevOpenHelper内部クラスを変更するか、独自のクラスを作成できます。とりあえず、サンプルを単純にするためにDevOpenHelperを編集することにしました。ただし、greendaoクラスを再生成すると、DevOpenHelperが上書きされることに注意してください。 「MyOpenHelper」のような独自のクラスを作成し、代わりにそれを使用することをお勧めします。
変更前は、DevOpenHelper.onUpgradeは次のようになっています。
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
すべてのテーブルを削除する代わりに、GreenDaoによって自動生成されるcreateAllTablesメソッドを見てください。
OnUpgradeを書き換えて、「oldVersion」がアップグレード元のバージョンかどうかを確認し、「新しい」テーブルのcreateTableメソッドのみを呼び出します。これが私のonUpgradeメソッドの外観です。
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " +
//Going from older schema to new schema
if(oldVersion == 3 && newVersion == 4)
{
boolean ifNotExists = false;
//Leave old tables alone and only create ones that didn't exist
//in the previous schema
NewTable1Dao.createTable(db, ifNotExists);
NewTable2Dao.createTable(db, ifNotExists);
NewTable3Dao.createTable(db, ifNotExists);
NewTable4Dao.createTable(db, ifNotExists);
}
else
{
dropAllTables(db, true);
onCreate(db);
}
}
新しい列を追加する方法も同様ですが、SQLを記述するか、greenDaoから自動生成されたSQL作成ステートメントを調べて活用する必要がある点が異なります。
単一の新しい列(NEW_COLUMN、それがINTEGERタイプであると想定)を既存のテーブル(EXISTING_TABLE)に追加するには、次のようにします。
db.execSQL("ALTER TABLE 'EXISTING_TABLE' ADD 'NEW_COLUMN' INTEGER");
今のところ、新しいテーブルを追加するだけなので、これはかなり単純なものになりました。うまくいけば、他の誰かがこれが便利だと思っています。
以前のユーザーがどこから来たとしても、更新を自動的に処理するために少し異なるアプローチをとっています。最初に、SQLDatabaseにメソッドonUpgradeを実装するクラスを作成しました
public abstract class AbstractMigratorHelper {
public abstract void onUpgrade(SQLiteDatabase db);
}
このクラスから、後で宣言するすべてのmigratorsヘルパーを継承します
それらの例を書きます
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を削除する必要があります。
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を使用している場合、コードを難読化するとクラス名が変更されるため、メソッドfind class by classが機能しない可能性があります。 AbstractMigratorHelperから拡張されるクラスを除外するために、プロガード構成ファイル(proguard-rules.pro)に例外を追加することを検討することをお勧めします。
# Avoid errors when upgrading database migrators
-keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper
少し違う方法でやります。
新しい@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);
}
}
}
最初の回答で@MBHが投稿した質問に回答する。また、私はこの投稿で答えを見つけられなかったため、追加しました。
GreenDAOは、build.gradleファイルのスキーマバージョン番号を使用します。 Gradleファイルには以下を含める必要があります
Android {
...
}
greendao {
schemaVersion 1
}
詳細については、この link を参照してください。次に、アップグレード時にこの数を2または任意の増分に変更します。その数に基づいて、Android.database.sqlite.SQLiteDatabase.DatabaseOpenHelper.JavaからのAPIの下のGreenDAO呼び出し
public DatabaseOpenHelper(Context context, String name, int version)
Sqlite DBアップグレードによる標準的なアプローチとして、以下のAPIを呼び出します
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
他の回答が示唆するように、このメソッドは派生クラスでオーバーライドでき、プロジェクト固有のアップグレードを処理できます。お役に立てれば。