Android: aktualizacja wersji DB i dodanie nowej tabeli

Utworzyłem już tabele sqlite dla mojej aplikacji, ale teraz chcę dodać nową tabelę do bazy danych.

Zmieniłem wersję DB jak poniżej

private static final int DATABASE_VERSION = 2;

I dodano łańcuch do tworzenia tabeli

private static final String DATABASE_CREATE_color = 
   "CREATE TABLE IF NOT EXISTS files(color text, incident_id text)";

onCreate i onUpgrade Jak poniżej:

@Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE_incident);
        database.execSQL(DATABASE_CREATE_audio);
        database.execSQL(DATABASE_CREATE_video);
        database.execSQL(DATABASE_CREATE_image);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //drop table and add new tables when version 2 released.
        db.execSQL(DATABASE_CREATE_color);

    }

Ale z jakiegoś powodu nowa tabela nie jest tworzona. Co robię źle?

Author: Jeff Axelrod, 2011-11-15

5 answers

1. O OnCreate () i onUpgrade()

onCreate(..) jest wywoływany, gdy aplikacja jest świeżo zainstalowana. onUpgrade jest wywoływany za każdym razem, gdy aplikacja jest aktualizowana i uruchamiana, a wersja bazy danych nie jest taka sama.

2. Zwiększenie wersji db

Potrzebujesz konstruktora typu:

MyOpenHelper(Context context) {
   super(context, "dbname", null, 2); // 2 is the database version
}

Ważne: zwiększenie samej wersji aplikacji nie wystarczy do wywołania onUpgrade!

3. Nie zapomnij o nowym użytkownicy!

Nie zapomnij dodać

database.execSQL(DATABASE_CREATE_color);

Do metody onCreate() lub nowo zainstalowanych aplikacji będzie brakowało tabeli.

4. Jak radzić sobie z wieloma zmianami w bazie danych w czasie

Gdy masz kolejne aktualizacje aplikacji, z których kilka ma uaktualnienia bazy danych, chcesz mieć pewność, aby sprawdzić oldVersion:

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   switch(oldVersion) {
   case 1:
       db.execSQL(DATABASE_CREATE_color);
       // we want both updates, so no break statement here...
   case 2:
       db.execSQL(DATABASE_CREATE_someothertable); 
   }
}

W ten sposób, gdy użytkownik aktualizuje z wersji 1 do wersji 3, otrzymuje obie aktualizacje. Gdy użytkownik aktualizuje z wersji 2 do 3, po prostu dostają aktualizację wersji 3... W końcu nie możesz liczyć na 100% bazy użytkowników, aby uaktualnić za każdym razem, gdy wydajesz aktualizację. Czasami pomijają update lub 12:)

5. Utrzymywanie numerów wersji pod kontrolą podczas tworzenia

I wreszcie... wywołanie

adb uninstall <yourpackagename>

Całkowicie odinstalowuje aplikację. Po ponownej instalacji masz gwarancję trafienia onCreate, co zapobiega konieczności zwiększania wersji bazy danych do stratosfery w miarę rozwoju...

 255
Author: jkschneider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-30 21:47:55

Twój kod wygląda poprawnie. Sugeruję, że baza myśli, że jest ulepszona. Jeśli wykonałeś projekt po zwiększeniu numeru wersji, ale przed dodaniem wywołania execSQL, baza danych na Twoim urządzeniu testowym / emulatorze może już wierzyć, że jest w wersji 2.

Szybkim sposobem, aby to zweryfikować, byłaby zmiana numeru wersji na 3-Jeśli uaktualni się po tym, wiesz, że było to tylko dlatego, że Twoje urządzenie wierzyło, że zostało już zaktualizowane.

 9
Author: Greyson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 08:51:13

Możesz użyć metody sqliteopenhelper onUpgrade. W metodzie onUpgrade otrzymujesz oldVersion jako jeden z parametrów.

W onUpgrade Użyj switch, a w każdym z case Użyj numeru wersji, aby śledzić bieżącą wersję bazy danych.

Najlepiej jest przełączyć się z oldVersion do newVersion, zwiększając version o 1 na raz, a następnie krok po kroku aktualizować bazę danych. Jest to bardzo pomocne, gdy ktoś z bazy danych w wersji 1 aktualizuje aplikację po długim czasie, do wersja korzystająca z bazy danych w wersji 7 i aplikacja zaczyna się zawieszać z powodu pewnych niekompatybilnych zmian.

Następnie aktualizacje w bazie danych będą wykonywane krok po kroku, obejmując wszystkie możliwe przypadki, tj. włączając zmiany w bazie danych wykonane dla każdej nowej wersji i tym samym zapobiegając awarii aplikacji.

Na przykład:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    switch (oldVersion) {
    case 1:
        String sql = "ALTER TABLE " + TABLE_SECRET + " ADD COLUMN " + "name_of_column_to_be_added" + " INTEGER";
        db.execSQL(sql);
        break;

    case 2:
        String sql = "SOME_QUERY";
        db.execSQL(sql);
        break;
    }

}
 2
Author: Vijesh Jat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-20 18:10:39

@ Jkschneider ' s answer is right. Istnieje jednak lepsze podejście.

Zapisz potrzebne zmiany w pliku sql dla każdej aktualizacji, jak opisano w linku https://riggaroo.co.za/android-sqlite-database-use-onupgrade-correctly/

From_1_to_2.sql

ALTER TABLE books ADD COLUMN book_rating INTEGER;

From_2_to_3.sql

ALTER TABLE books RENAME TO book_information;

From_3_to_4.sql

ALTER TABLE book_information ADD COLUMN calculated_pages_times_rating INTEGER;
UPDATE book_information SET calculated_pages_times_rating = (book_pages * book_rating) ;
To .pliki sql będą wykonywane w metodzie onUpgrade() zgodnie z wersją baza danych.

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 4;

    private static final String DATABASE_NAME = "database.db";
    private static final String TAG = DatabaseHelper.class.getName();

    private static DatabaseHelper mInstance = null;
    private final Context context;

    private DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
    }

    public static synchronized DatabaseHelper getInstance(Context ctx) {
        if (mInstance == null) {
            mInstance = new DatabaseHelper(ctx.getApplicationContext());
        }
        return mInstance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(BookEntry.SQL_CREATE_BOOK_ENTRY_TABLE);
        // The rest of your create scripts go here.

    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.e(TAG, "Updating table from " + oldVersion + " to " + newVersion);
        // You will not need to modify this unless you need to do some android specific things.
        // When upgrading the database, all you need to do is add a file to the assets folder and name it:
        // from_1_to_2.sql with the version that you are upgrading to as the last version.
        try {
            for (int i = oldVersion; i < newVersion; ++i) {
                String migrationName = String.format("from_%d_to_%d.sql", i, (i + 1));
                Log.d(TAG, "Looking for migration file: " + migrationName);
                readAndExecuteSQLScript(db, context, migrationName);
            }
        } catch (Exception exception) {
            Log.e(TAG, "Exception running upgrade script:", exception);
        }

    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    private void readAndExecuteSQLScript(SQLiteDatabase db, Context ctx, String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            Log.d(TAG, "SQL script file name is empty");
            return;
        }

        Log.d(TAG, "Script found. Executing...");
        AssetManager assetManager = ctx.getAssets();
        BufferedReader reader = null;

        try {
            InputStream is = assetManager.open(fileName);
            InputStreamReader isr = new InputStreamReader(is);
            reader = new BufferedReader(isr);
            executeSQLScript(db, reader);
        } catch (IOException e) {
            Log.e(TAG, "IOException:", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    Log.e(TAG, "IOException:", e);
                }
            }
        }

    }

    private void executeSQLScript(SQLiteDatabase db, BufferedReader reader) throws IOException {
        String line;
        StringBuilder statement = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            statement.append(line);
            statement.append("\n");
            if (line.endsWith(";")) {
                db.execSQL(statement.toString());
                statement = new StringBuilder();
            }
        }
    }
}

Przykładowy projekt znajduje się również w tym samym linku: https://github.com/riggaroo/AndroidDatabaseUpgrades

 1
Author: oiyio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-23 21:25:17

Obsługa wersji baz danych jest bardzo ważną częścią tworzenia aplikacji. Zakładam, że masz już klasę AppDbHelper rozszerzającą SQLiteOpenHelper. Po jej rozszerzeniu należy zaimplementować metodę onCreate i onUpgrade.

  1. Gdy onCreate i onUpgrade metody nazywane

    • onCreate wywołane po ponownym zainstalowaniu aplikacji.
    • onUpgrade wywołane po aktualizacji aplikacji.
  2. Organizowanie wersji baz danych Zarządzam wersjami metodami klasowymi. Utwórz implementacja migracji interfejsu. Np. dla pierwszej wersji create MigrationV1 Klasa, drugiej wersji create MigrationV1ToV2 (są to moje nazewnictwo)


    public interface Migration {
        void run(SQLiteDatabase db);//create tables, alter tables
    }

Przykład migracji:

public class MigrationV1ToV2 implements Migration{
      public void run(SQLiteDatabase db){
        //create new tables
        //alter existing tables(add column, add/remove constraint)
        //etc.
     }
   }
  1. używanie klas migracji

onCreate: ponieważ onCreate zostanie wywołana podczas świeżo zainstalowanej aplikacji, musimy również wykonać wszystkie migracje (aktualizacje wersji bazy danych). Więc onCreate will wygląda tak:

public void onCreate(SQLiteDatabase db){
        Migration mV1=new MigrationV1();
       //put your first database schema in this class
        mV1.run(db);
        Migration mV1ToV2=new MigrationV1ToV2();
        mV1ToV2.run(db);
        //other migration if any
  }

onUpgrade: metoda ta zostanie wywołana, gdy aplikacja jest już zainstalowana i jest aktualizowana do nowej wersji aplikacji. Jeśli aplikacja zawiera jakiekolwiek zmiany w bazie danych, to wszystkie zmiany w bazie danych należy umieścić w nowej klasie migracji i wersji bazy danych increment.

Na przykład, powiedzmy, że użytkownik ma zainstalowaną aplikację, która ma bazę danych w wersji 1, a teraz Wersja bazy danych jest aktualizowana do wersji 2(wszystkie aktualizacje schematu przechowywane w MigrationV1ToV2). Teraz po aktualizacji aplikacji, musimy uaktualnić bazę danych, stosując zmiany schematu bazy danych w MigrationV1ToV2, Jak to:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion < 2) {
        //means old version is 1
        Migration migration = new MigrationV1ToV2();
        migration.run(db);
    }
    if (oldVersion < 3) {
        //means old version is 2
    }
}

Uwaga: wszystkie uaktualnienia (wymienione w onUpgrade) w schemacie bazy danych powinny być wykonywane w onCreate

 1
Author: VVJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-26 17:16:40