web-dev-qa-db-ja.com

onUpgradeメソッドが呼び出されたことはありますか?

onUpgradeSQLiteOpenHelper のメソッドが呼び出されたことはありますか?もしそうなら、それはいつ、何によって呼び出されますか?開発者から呼び出されないのなら、なぜそこにあるのでしょうか。その関数で実際に何が起こりますか?すべてのテーブルを削除する例を見てきましたが、コメントには、すべてのテーブルを削除することはあなたがすべきことではないというものがあります。助言がありますか?

33
Mohit Deshpande

これは、開いているデータベースのバージョンよりも新しいバージョンでSQLiteOpenHelperを構築するときに呼び出されます。何をするかは、古いバージョンと新しいバージョンの間で行われたデータベースの変更によって異なります。変更されたテーブルを削除しない場合は、変更が追加された列以外のものに注目している場合のみです。次に、ALTER TABLEステートメントを使用して、新しい列をテーブルの署名に追加できます。

21
ognian

onUpgrade()が呼び出された正確な瞬間を知りたい方は、getReadableDatabase()またはgetWriteableDatabase()のいずれかを呼び出している間です。

確実にトリガーされる方法がわからない場合は、次のように答えます。SqLiteOpenHelperのコンストラクターに提供されたデータベースバージョンが更新されたときにトリガーされます。これが例です

public class dbSchemaHelper extends SQLiteOpenHelper {

private String sql;
private final String D_TAG = "FundExpense";
//update this to get onUpgrade() method of sqliteopenhelper class called
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager";

public dbSchemaHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    // TODO Auto-generated constructor stub
}

今から... onUpgrade()

@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER";
    arg0.execSQL(sql);
}
36
lazyList

sQLiteOpenHelperを使用している場合、DBバージョンを変更するたびにonUpgradeが呼び出されます。これが機能するための追加要件があります。データベース名は同じままである必要があります。

Old Version:
dbName = "mydb.db"
dbVersion = 1

New Version:
dbName = "mydb.db"
dbVersion = 2

コンテンツプロバイダーのonCreateで、これらのパラメーターを受け取るSQLiteOpenHelperのインスタンスを作成します。 SQLiteOpenHelperの実装は次のようになります。

public static final class MySQLiteOpenHelper extends SQLiteOpenHelper {

        public MySQLiteOpenHelper(Context context, int dbVersion, String dbName) {
            super(context, dbName, null, dbVersion);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            //Code to create your db here
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // Code to upgrade your db here
        }

}
28
dev.serghini

すべての投稿を確認してデバッグコードを実行すると、onUpgradeがいつ呼び出されるかがわかりませんでした。 Androidには重大な欠陥があると思い始めていました。

このページの情報から、最終的な解決策にたどり着きました。すべての貢献者に感謝します!

これは私のためにそれを解決しました...

public class DatabaseHelper extends SQLiteOpenHelper {
    public static String TAG = DatabaseHelper.class.getName();
    private static final int DATABASE_VERSION = 42;
    private static final String DATABASE_NAME = "app_database";
    private static final String OLD_TABLE = "old_and_useless";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion ) {
        if( newVersion > oldVersion) {
            Log.d( TAG, "cool! you noticed." );

            db.execSQL( "DROP TABLE IF EXISTS " + OLD_TABLE );
            // other calls like onCreate if necessary

        } else {
            Log.d( TAG, "Hey! didn't you see me?" );
        }

    }

    public void checkDatabaseVersion() {
        SQLiteDatabase db = this.getWritableDatabase();

        // if the DATABASE_VERSION is newer
        //    onUpgrade is called before this is reached
    }


    // other code removed for readability...
}

GetWritableDatabase()とgetReadableDatabase()がonUpgrade呼び出しをもたらすのは事実です。他の方法は私のニーズに合っているので、チェックしませんでした。

読み続けてください、キッカーが来ています...

私の最初のアクティビティのこのコードは、デバッグ中にデータベースのバージョンが更新されていることにようやく気づいたときに私を啓発しました... ugh! ==

DatabaseHelper dbHelper = new DatabaseHelper( this );
dbHelper.checkDatabaseVersion();

注:DatabaseHelperコンストラクターを呼び出すとdbバージョンが更新されます

コンストラクターの呼び出し後、dbは新しいバージョンでタグ付けされました。 getWritableDatabase()またはgetReadableDatabase()を呼び出す前にアプリを強制終了すると、新しいバージョンが使用されます。その後、DATABASE_VERSIONが再び増加するまで、新しい実行がonUpgradeメソッドを呼び出すことはありません。 (ため息!今ではばかばかしいほど明白に見えます:)

私の提案は、アプリの初期段階にある種の「checkDatabaseVersion()」を追加することです。または、SQLiteOpenHelperオブジェクトを作成する場合は、アプリが停止する前に、必ずいずれかのメソッド(getWritableDatabase()、getReadableDatabase()など)を呼び出してください。

これにより、他の誰かが同じ頭を掻くのを防ぐことができれば幸いです!...:p

4
RobinM

SqliteOpenHelperソースコードを調べると、onCreate()onUpgrade()およびonDowngradegetWritableDatabase()またはgetReadableDatabase()メソッド。

public SQLiteDatabase getWritableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(true);
    }
}
public SQLiteDatabase getReadableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(false);
    }
}

private SQLiteDatabase getDatabaseLocked(boolean writable) {
    if (mDatabase != null) {
        if (!mDatabase.isOpen()) {
            // Darn!  The user closed the database by calling mDatabase.close().
            mDatabase = null;
        } else if (!writable || !mDatabase.isReadOnly()) {
            // The database is already open for business.
            return mDatabase;
        }
    }
          . . . . . .  

        final int version = db.getVersion();
        if (version != mNewVersion) {
            if (db.isReadOnly()) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + mName);
            }

            db.beginTransaction();
            try {
                if (version == 0) {
                    onCreate(db);
                } else {
                    if (version > mNewVersion) {
                        onDowngrade(db, version, mNewVersion);
                    } else {
                        onUpgrade(db, version, mNewVersion);
                    }
                }
                db.setVersion(mNewVersion);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }

        onOpen(db);

        if (db.isReadOnly()) {
            Log.w(TAG, "Opened " + mName + " in read-only mode");
        }

        mDatabase = db;
        return db;
    } finally {
        mIsInitializing = false;
        if (db != null && db != mDatabase) {
            db.close();
        }
    }
}
2
Folyd

getReadableDatabaseまたはgetWritableDatabaseを呼び出すと、実際にはになります。

詳細:

SQLiteOpenHelperという変数に格納されているmNewVersionのコンストラクターでバージョン番号を渡します。それでおしまい。この時点では何も起こりません。

GetReadableDatabaseまたはgetWritableDatabaseを呼び出すたびに、getDatabaseLockedというメソッドが呼び出されます。このメソッドは、データベースの既存のバージョン番号を取得し、それをmNewVersionと比較します。

  1. 指定された名前のデータベースが存在しない場合は、onCreateを呼び出します。
  2. 新しいバージョンが古いバージョンよりも大きい場合は、onUpgradeを呼び出します。
  3. 新しいバージョンが既存のバージョンよりも低い場合、例外がスローされます。
  4. それらが等しい場合は、先に進んでデータベースを開きます。

onCreateとonUpgradeに何を書くべきですか?

onCreateには、スキーマを初めて作成するコードが含まれている必要があります。

onUpgradeは最初に呼び出されないため、最初は空のままにしておくことができます。後の段階でテーブル構造を変更したい場合は、そのコードをここに入れる必要があります。

SQLiteOpenHelper.Java(ソースコード)

public SQLiteDatabase getWritableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(true);
    }
}

 public SQLiteDatabase getReadableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(false);
    }
}

private SQLiteDatabase getDatabaseLocked(boolean writable) {
   .
   .

     final int version = db.getVersion();

        if (version != mNewVersion) {
            if (db.isReadOnly()) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + mName);
            }

            db.beginTransaction();
            try {
                if (version == 0) {
                    onCreate(db);
                } else {
                    if (version > mNewVersion) {
                        onDowngrade(db, version, mNewVersion);
                    } else {
                        onUpgrade(db, version, mNewVersion);
                    }
                }
                db.setVersion(mNewVersion);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
       }

       onOpen(db);
 }
1
Siva Prakash