web-dev-qa-db-ja.com

データベースのORMLiteアップデート

私は実際にORMLiteライブラリを使用するアプリを開発しています(これは素晴らしいことです)が、私はそれを使用する初心者です。

デバイス内のデータベースの更新について質問があります。

誰かが私のアプリをGooglePlayにダウンロードしたとしましょう。数か月後、私は確かにいくつかのテーブルに新しいエントリを入力します。

この人がアプリの更新を行っているときに、データベースを新しいエントリで更新し、古いエントリをその中に保持するにはどうすればよいですか。

より明確にするために、ユーザーが私のアプリで質問に答えたと想像してください。新しい質問を紹介するとき、彼が私のアプリを更新するときに、どのようにそれらをデータベースに挿入できますかそして質問を保持しますすでに回答済みですか?

17
Alexis C.

この人がアプリの更新を行っているときに、データベースを新しいエントリで更新し、古いエントリをその中に保持するにはどうすればよいですか。

アイデアは、onUpgrade(...)メソッドに渡されるバージョン番号を使用することです。 ORMLite の場合、OrmLiteSqliteOpenHelper.onUpgrade(...)メソッドはoldVersionnewVersionの数値を取ります。次に、古い形式からデータを変換してスキーマを更新できる変換コードをアプリケーションに書き込むことができます。

詳細については、 スキーマのアップグレードに関するORMLiteドキュメント を参照してください。

引用すると、次のようなことができます。

if (oldVersion < 2) {
  // we added the age column in version 2
  dao.executeRaw("ALTER TABLE `account` ADD COLUMN age INTEGER;");
}
if (oldVersion < 3) {
  // we added the weight column in version 3
  dao.executeRaw("ALTER TABLE `account` ADD COLUMN weight INTEGER;");
}

変換する必要のある既存のデータがある場合は、可能であればSQLで変換を行う必要があります。

別の方法は、同じテーブル名を指すAccountエンティティとOldAccountエンティティを持つことです。次に、OldAccountを使用してoldAccountDaoエンティティを読み込み、それらをAccountエンティティに変換してから、accountDaoを使用して同じテーブルに更新します。ここでは、オブジェクトキャッシュに注意する必要があります。

私はそれをこのようにします:

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

    switch (oldVersion) {
    case 1:
        updateFromVersion1(database, connectionSource, oldVersion, newVersion);
        break;
    case 2:
        updateFromVersion2(database, connectionSource, oldVersion, newVersion);
        break;
    default:
        // no updates needed
        break;
    }

}

private void updateFromVersion1(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
    // do some stuff here
    onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}

private void updateFromVersion2(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
    // do some stuff here
    onUpgrade(database, connectionSource, oldVersion + 1, newVersion);
}

これにより、ユーザーのデータベースは、ユーザーが使用するデータベースのバージョンに関係なく段階的に更新されます。

8
Terel

情報がほとんどなく、テーブル構造が変更されているかどうかは明確ではありません。

a)データベース構造を変更しない場合。

1以前に保存したバージョン(設定など)を現在のバージョンでチェックし始めたときのプログラムの新しいバージョン(PackageManager.getPackageInfoを参照)

保存済み= 0-ユーザーが新しいバージョンをインストールしたばかり

保存済み<現在-ユーザーがプログラムを更新します

2ベースに新しいデータを追加します

3現在のバージョンを設定に保存します

b)テーブル構造が変更された場合(フィールドの追加または削除)

1データベースのバージョン番号を増やします(extends OrmLiteSqliteOpenHelperクラスを参照してください)

2ユーザーが最初にプログラムに遭遇すると、メソッド 'onUpgrade'が(extends OrmLiteSqliteOpenHelperクラスで)呼び出され、古いバージョン番号と新しいバージョン番号に転送されます。

  • キャッシュ内の既存のデータを読み取ります(temp)
  • テーブルを再作成
  • キャッシュからのデータと新しいデータを追加します
3
avesha

アップグレードのたびにデータベースを削除したり、各フィールドを追加した後に更新コードを記述したりするのは好きではないので、...

私は次のようにしようとしています:

@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
    ArrayList<String> tableNames = getTableNames(database);
    for (Class clazz : daoClasses) {
        try {
            Annotation annotation = clazz.getAnnotation(DatabaseTable.class);
            if (annotation != null && annotation instanceof DatabaseTable) {
                String tableName = ((DatabaseTable) annotation).tableName();
                if (tableName.isEmpty()) {
                    tableName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
                }
                if(!tableNames.contains(tableName)){
                    TableUtils.createTable(connectionSource, clazz);
                } else {
                    addColumns(database, tableName, clazz);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

private ArrayList<String> getTableNames(SQLiteDatabase database){
    ArrayList<String> tableNames = new ArrayList<>();
    Cursor cursor = database.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
    if (cursor.moveToFirst()) {
        while ( !cursor.isAfterLast() ) {
            tableNames.add(cursor.getString(0));
            cursor.moveToNext();
        }
    }
    cursor.close();
    return tableNames;
}

private void addColumns(SQLiteDatabase database, String tableName, Class clazz){
    Cursor mCursor = database.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null);
    for (Field field : clazz.getDeclaredFields()) {
        try {
            DatabaseField annotationField = field.getAnnotation(DatabaseField.class);
            if (annotationField != null && !annotationField.foreign()){
                String columnName = field.getName();
                boolean hasColumn = mCursor.getColumnIndex(columnName) != -1;
                if (!hasColumn) {
                    String columnType = field.getType().getSimpleName();
                    if(columnType.equals(String.class.getSimpleName())){
                        columnType = "TEXT";
                    } else {
                        columnType = columnType.toUpperCase();
                    }
                    database.execSQL(MessageFormat.format("ALTER TABLE `{0}` ADD COLUMN {1} {2};", tableName, columnName, columnType));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    mCursor.close();
}

このコードがもっと良くなることを願っています。

ここでは、daoから削除された古いテーブルと列を削除したり、外部フィールドを作成したりしません(必要かどうかはわかりません)。

2
John