Wann wird SQLiteOpenHelper onCreate () / onUpgrade () ausgeführt?


293

Ich habe meine Tabellen in meinem erstellt, SQLiteOpenHelper onCreate()aber erhalten

SQLiteException: no such table

oder

SQLiteException: no such column

Fehler. Warum?

HINWEIS:

(Dies ist die zusammengeführte Zusammenfassung von zehn ähnlichen Fragen pro Woche. Es wird versucht, hier eine "kanonische" Community-Wiki-Frage / Antwort bereitzustellen, damit all diese Fragen an eine gute Referenz weitergeleitet werden können.)


12
@Ndupza Dies ist kein wirkliches Problem von mir, ich habe es einfach satt, zum N-ten Mal dieselbe Antwort / denselben Kommentar zu schreiben.
Laalto

Antworten:


352

SQLiteOpenHelper onCreate()und onUpgrade()Rückrufe werden aufgerufen, wenn die Datenbank tatsächlich geöffnet wird, beispielsweise durch einen Aufruf von getWritableDatabase(). Die Datenbank wird nicht geöffnet, wenn das Datenbank-Hilfsobjekt selbst erstellt wird.

SQLiteOpenHelperVersionen der Datenbankdateien. Die Versionsnummer ist das intan den Konstruktor übergebene Argument . In der Datenbankdatei wird die Versionsnummer in gespeichert PRAGMA user_version.

onCreate()wird nur ausgeführt, wenn die Datenbankdatei nicht vorhanden war und gerade erstellt wurde. Bei onCreate()erfolgreicher Rückgabe (keine Ausnahme) wird davon ausgegangen, dass die Datenbank mit der angeforderten Versionsnummer erstellt wurde. Als Implikation sollten Sie SQLExceptions nicht in sich onCreate()selbst fangen .

onUpgrade()wird nur aufgerufen, wenn die Datenbankdatei vorhanden ist, die gespeicherte Versionsnummer jedoch niedriger ist als im Konstruktor angefordert. Das onUpgrade()sollte das Tabellenschema auf die angeforderte Version aktualisieren.

Wenn Sie das Tabellenschema in code ( onCreate()) ändern , sollten Sie sicherstellen, dass die Datenbank aktualisiert wird. Zwei Hauptansätze:

  1. Löschen Sie die alte Datenbankdatei, damit onCreate()sie erneut ausgeführt wird. Dies wird häufig zur Entwicklungszeit bevorzugt, wenn Sie die Kontrolle über die installierten Versionen haben und Datenverlust kein Problem darstellt. Einige Möglichkeiten zum Löschen der Datenbankdatei:

    • Deinstallieren Sie die Anwendung. Verwenden Sie den Anwendungsmanager oder adb uninstall your.package.namedie Shell.

    • Anwendungsdaten löschen. Verwenden Sie den Anwendungsmanager.

  2. Inkrementieren Sie die Datenbankversion, damit sie onUpgrade()aufgerufen wird. Dies ist etwas komplizierter, da mehr Code benötigt wird.

    • Bei Upgrades des Entwicklungszeitschemas, bei denen Datenverlust kein Problem darstellt, können Sie einfach execSQL("DROP TABLE IF EXISTS <tablename>")Ihre vorhandenen Tabellen entfernen und onCreate()die Datenbank neu aufrufen .

    • Für freigegebene Versionen sollten Sie die Datenmigration in implementieren onUpgrade() damit Ihre Benutzer ihre Daten nicht verlieren.


2
@Laalto // Datenmigration in onUpgrade () // Kannst du das bitte erklären.
bCliks

2
@bala Nicht im Rahmen dieser Frage / Antwort. Wenn Sie eine Frage haben, können Sie diese gerne als Frage posten.
Laalto

2
@Jaskey Die Versionsnummer ist für Ihren Code, dh für welche Schemaversion der Code voraussichtlich ausgeführt wird. Wenn die Datei älter ist (aus einer früheren Version Ihrer App), muss sie aktualisiert werden.
Laalto

4
Daher muss ich die DB-VERSION in SQLiteHelper jedes Mal hart codieren, wenn ich das Schema ändere. Wenn die alte App ausgeführt wird und die Datenbankverbindung abgerufen wird und festgestellt wird, dass sie alt ist, wird onUpgrade anstelle von onCreate überprüft richtig?
Jaskey

2
Danke ! Das macht für mich Sinn. Bitte überprüfen Sie, ob ich es gut verstehe. Also müssen wir 1. jedes Mal, wenn wir das Schema aktualisieren, die Variable DB_VERSION (Hardcode) ändern. 2. onUpdate()Überprüfen Sie in jede alte Version und führen Sie eine ordnungsgemäße Datenmigration durch. Und dann, wenn ein Benutzer seine App aktualisiert (er hat alte Datenbankdateien), onUpgradewird ausgelöst, und wenn der Benutzer neu installiert wird, onCreate()wird ausgelöst.
Jaskey

97

Um hier fehlende Punkte weiter hinzuzufügen, gemäß der Anfrage von Jaskey

Die Datenbankversion wird in der SQLiteDatenbankdatei gespeichert.

catch ist der Konstruktor

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

Wenn der Datenbank- nameHilfskonstruktor mit einem (2. Parameter) aufgerufen wird, prüft die Plattform, ob die Datenbank vorhanden ist oder nicht, und ob die Datenbank vorhanden ist, ruft die Versionsinformationen aus dem Datenbankdateikopf ab und löst den richtigen Rückruf aus

Wie bereits in der älteren Antwort erläutert, wird die Datenbank mit dem Namen ausgelöst, wenn sie nicht vorhanden ist onCreate.

Die folgende Erklärung erläutert den onUpgradeFall anhand eines Beispiels.

Angenommen, Ihre erste Version der Anwendung hatte die DatabaseHelper(erweiterte SQLiteOpenHelper) Version, bei der der Konstruktor übergeben wurde, 1und dann haben Sie eine aktualisierte Anwendung mit dem neuen Quellcode bereitgestellt, dessen Version als Plattform übergeben wurde 2, und dann automatisch, wenn die DatabaseHelperPlattform ausgelöst wirdonUpgrade indem die Datei bereits vorhanden ist. Die Version ist jedoch niedriger als die aktuelle Version, die Sie übergeben haben.

Angenommen, Sie planen, eine dritte Version der Anwendung mit der 3Datenbankversion as anzugeben (die Datenbankversion wird nur erhöht, wenn das Datenbankschema geändert werden soll). Bei solchen inkrementellen Upgrades müssen Sie die Upgrade-Logik von jeder Version inkrementell schreiben, um einen besser wartbaren Code zu erhalten

Beispiel Pseudocode unten:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  switch(oldVersion) {
    case 1:
       //upgrade logic from version 1 to 2
    case 2:
       //upgrade logic from version 2 to 3
    case 3:
       //upgrade logic from version 3 to 4
       break;
    default:
       throw new IllegalStateException(
                "onUpgrade() with unknown oldVersion " + oldVersion);
  }
}

Beachten Sie die fehlende breakAussage in case 1und 2. Das meine ich mit inkrementellem Upgrade.

Angenommen, die alte Version ist 2und die neue Version ist 4, dann aktualisiert die Logik die Datenbank von 2bis 3und dann bis4

Wenn die alte Version 3und die neue Version ist 4, wird nur die Upgrade-Logik für 3to ausgeführt4


1
Ich denke, Sie möchten, dass Ihr Switch (newVersion) stattdessen Switch (oldVersion) ist. Möglicherweise möchten Sie auch überprüfen, ob newVersion 4 ist (und nicht 5 oder 3; da Ihre Logik davon ausgeht, dass die neue Version 4 sein sollte). Wenn die alte Version 2 und die neue Version 5 ist, werden Sie dies auch tun Treffen Sie den Fall 4: und aktualisieren Sie von 3 auf 4 (was wahrscheinlich nicht zu erwarten ist).
Joe p

rechts - Tippfehler .. aber wenn die neue Version 5 ist -> dann wird immer IllegalStateException ausgelöst und der Entwickler wird dies beheben, indem er Fall 5 hinzufügt ..
Aun

1
Was ist, wenn der Benutzer seine App nur von Version 2 auf 3 aktualisiert? Auch in diesem Fall werden alle Fälle bis Fall 4 ausgeführt.
Paramvir Singh

6
@param Benutzer kann das nicht. Er kann nur 2 auf die neueste Version (hier 4) aktualisieren.
Habeeb Perwad

20

onCreate()

  1. Wenn wir die Datenbank zum ersten Mal erstellen (dh die Datenbank ist nicht vorhanden), onCreate()erstellen Sie eine Datenbank mit der übergebenen Version SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()Die Methode erstellt die von Ihnen definierten Tabellen und führt jeden anderen von Ihnen geschriebenen Code aus. Diese Methode wird jedoch nur aufgerufen, wenn die SQLite-Datei im Datenverzeichnis Ihrer App fehlt ( /data/data/your.apps.classpath/databases).

  3. Diese Methode wird nicht aufgerufen, wenn Sie Ihren Code geändert und im Emulator neu gestartet haben. Wenn Sie onCreate()ausführen möchten , müssen Sie adb verwenden, um die SQLite-Datenbankdatei zu löschen.

onUpgrade()

  1. SQLiteOpenHelper sollte den Super-Konstruktor aufrufen.
  2. Die onUpgrade()Methode wird nur aufgerufen, wenn die Versions-Ganzzahl größer ist als die aktuelle Version, die in der App ausgeführt wird.
  3. Wenn die onUpgrade()Methode aufgerufen werden soll, müssen Sie die Versionsnummer in Ihrem Code erhöhen.

1
Könnten Sie bitte Ihre Antwort näher erläutern und etwas mehr Beschreibung der von Ihnen angebotenen Lösung hinzufügen?
Abarisone

10

Vielleicht bin ich zu spät, aber ich möchte meine kurze und süße Antwort teilen. Bitte überprüfen Sie die Antwort auf das gleiche Problem. Es wird dir definitiv helfen. Keine tieferen Spezifikationen mehr.

Wenn Sie sich hinsichtlich der Syntax zum Erstellen einer Tabelle sicher sind, kann dies passieren, wenn Sie eine neue Spalte in derselben Tabelle hinzufügen.

1) Deinstallieren Sie von Ihrem Gerät und führen Sie es erneut aus.

ODER

2) Einstellung -> App -> ClearData

ODER

3) Ändern Sie DATABASE_VERSIONIhre "DatabaseHandler" -Klasse (Wenn Sie eine neue Spalte hinzugefügt haben, wird diese automatisch aktualisiert)

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

ODER

4) Änderung DATABASE_NAMEin Ihrer "DatabaseHandler" -Klasse (Ich hatte das gleiche Problem. Aber es gelingt mir, wenn ich mich ändere DATABASE_NAME.)


Ich habe meine eigene Datenbank und verwende die SQLiteAssetHelper-Klasse. Also habe ich die DB vorher per SQL-Skript erstellt und die Datenbank wurde erstellt. Mit SQLiteAssetHelper konnte die Datenbank erst kopiert werden, wenn die App vom Emulator oder Gerät deinstalliert wurde, da es sich um eine Datenbank mit derselben Version handelte.
Behzad

4

Punkte, die Sie beim Erweitern beachten sollten SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Dies sollte in der ersten Zeile des Konstruktors aufgerufen werden
  2. überschreiben onCreateund onUpgrade(falls erforderlich)
  3. onCreatewird nur aufgerufen, wenn getWritableDatabase()oder getReadableDatabase()ausgeführt wird. Und dies wird nur einmal aufgerufen, wenn eine DBNameim ersten Schritt angegebene nicht verfügbar ist. Sie können die onCreateMethode create table query on method hinzufügen
  4. Wenn Sie eine neue Tabelle hinzufügen möchten, ändern Sie DBversioneinfach die Abfragen in der onUpgradeTabelle oder deinstallieren Sie sie einfach und installieren Sie die App.

3

onCreate wird zum ersten Mal aufgerufen, wenn die Erstellung von Tabellen erforderlich ist. Wir müssen diese Methode überschreiben, indem wir das Skript für die Tabellenerstellung schreiben, das von SQLiteDatabase ausgeführt wird. execSQL-Methode. Nach der Ausführung in der ersten Bereitstellung wird diese Methode nicht mehr aufgerufen.

onUpgrade Diese Methode wird aufgerufen, wenn die Datenbankversion aktualisiert wird. Angenommen, bei der ersten Bereitstellung war die Datenbankversion 1, und bei der zweiten Bereitstellung wurde die Datenbankstruktur geändert, z. B. durch Hinzufügen einer zusätzlichen Spalte in der Tabelle. Angenommen, die Datenbankversion ist jetzt 2.


2

Sie können Datenbank & Tabelle wie erstellen

public class DbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "testdatbase.db";
private static final int VERSION = 1;

public DbHelper(Context context) {
    super(context, DBNAME, null, VERSION);
    // TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub
    db.execSQL("create table BookDb(id integer primary key autoincrement,BookName text,Author text,IssuedOn text,DueDate text,Fine text,Totalfine text");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS BookDb");
    onCreate(db);
  }
}

Hinweis: Wenn Sie eine andere Tabelle erstellen oder Spalten hinzufügen möchten oder keine solche Tabelle, erhöhen Sie einfach die VERSION


2

Die SQLite-Datenbank überschreibt zwei Methoden

1) onCreate (): Diese Methode wird nur einmal aufgerufen, wenn die Anwendung zum ersten Mal gestartet wird. Also hat es nur einmal angerufen

2) onUpgrade () Diese Methode wird aufgerufen, wenn wir die Datenbankversion ändern. Dann wird diese Methode aufgerufen. Sie wird zum Ändern der Tabellenstruktur verwendet, z. B. zum Hinzufügen einer neuen Spalte nach dem Erstellen des DB-Schemas


1

Eine solche gefundene Tabelle wird hauptsächlich dann nicht gefunden, wenn Sie die SQLiteOpenHelperKlasse nicht mit geöffnet haben getwritabledata()und zuvor auch den make-Konstruktor mit Datenbankname & Version aufrufen müssen. Und OnUpgradewird immer dann aufgerufen, wenn die in der SQLiteOpenHelperKlasse angegebene Versionsnummer einen Upgrade-Wert enthält .

Unten ist das Code-Snippet (Keine solche Spalte wurde möglicherweise aufgrund eines Buchstabens im Spaltennamen gefunden):

public class database_db {
    entry_data endb;
    String file_name="Record.db";
    SQLiteDatabase sq;
    public database_db(Context c)
    {
        endb=new entry_data(c, file_name, null, 8);
    }
    public database_db open()
    {
        sq=endb.getWritableDatabase();
        return this;
    }
    public Cursor getdata(String table)
    {
        return sq.query(table, null, null, null, null, null, null);
    }
    public long insert_data(String table,ContentValues value)
    {
        return sq.insert(table, null, value);
    }
    public void close()
    {
        sq.close();
    }
    public void delete(String table)
    {
        sq.delete(table,null,null);
    }
}
class entry_data extends SQLiteOpenHelper
{

    public entry_data(Context context, String name, SQLiteDatabase.CursorFactory factory,
                      int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase sqdb) {
        // TODO Auto-generated method stub

        sqdb.execSQL("CREATE TABLE IF NOT EXISTS 'YOUR_TABLE_NAME'(Column_1 text not null,Column_2 text not null);");

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
          onCreate(db);
    }

}

1

Wenn Sie vergessen, dem Konstruktor eine "Name" -String als zweites Argument anzugeben, wird eine "In-Memory" -Datenbank erstellt, die beim Schließen der App gelöscht wird.


0

Deinstallieren Sie Ihre Anwendung vom Emulator oder Gerät. Führen Sie die App erneut aus. (OnCreate () wird nicht ausgeführt, wenn die Datenbank bereits vorhanden ist.)


0

Ihr Datenbankname muss mit .db enden. Außerdem müssen Ihre Abfragezeichenfolgen einen Terminator (;) haben.


0

Überprüfen Sie Ihre Abfrage erneut in Ihrer DatabaseHandler / DatabaseManager-Klasse (je nachdem, welche Sie genommen haben).


0

In meinem Fall bekomme ich Artikel aus der XML-Datei mit <string-array>, in der ich <item>s speichere . In diesen <item>s halte ich SQL-Strings und wende sie einzeln mit an databaseBuilder.addMigrations(migration). Ich habe einen Fehler gemacht, vergessen, \vor dem Zitat hinzuzufügen und bekam die Ausnahme:

android.database.sqlite.SQLiteException: keine solche Spalte: some_value (Code 1 SQLITE_ERROR): beim Kompilieren: INSERT INTO table_name (id, name) VALUES (1, some_value)

Das ist also eine richtige Variante:

<item>
    INSERT INTO table_name(id, name) VALUES(1, \"some_value\")
</item>

-2

Bei der Methode von Sqliteopenhelper werden Methoden erstellt und aktualisiert. Create wird verwendet, wenn eine Tabelle zum ersten Mal erstellt wird, und die Upgrade-Methode wird jedes Mal aufgerufen, wenn die Spaltennummer der Tabelle geändert wird.


Die onUpgrade-Methode wird aufgerufen, wenn die Datenbankversion zunimmt, nicht, wenn die Anzahl der Spalten geändert wird. Ref: developer.android.com/reference/android/database/sqlite/… , int, int)
Roger Huang
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.