Quando viene eseguito SQLiteOpenHelper onCreate () / onUpgrade ()?


293

Ho creato le mie tabelle nel mio SQLiteOpenHelper onCreate()ma ho ricevuto

SQLiteException: no such table

o

SQLiteException: no such column

errori. Perché?

NOTA:

(Questo è il riassunto combinato di decine di domande simili ogni settimana. Tentativo di fornire una domanda / risposta wiki canonica della comunità qui in modo che tutte quelle domande possano essere indirizzate a un buon riferimento.)


12
@Ndupza Questo non è un mio vero problema, stufo solo di scrivere la stessa risposta / commento per l'ennesima volta.
laalto,

Risposte:


352

SQLiteOpenHelper onCreate()e i onUpgrade()callback vengono richiamati quando il database viene effettivamente aperto, ad esempio da una chiamata a getWritableDatabase(). Il database non viene aperto quando viene creato l'oggetto helper del database stesso.

SQLiteOpenHelperversioni i file di database. Il numero di versione è l' intargomento passato al costruttore . Nel file di database, il numero di versione è memorizzato in PRAGMA user_version.

onCreate()viene eseguito solo quando il file di database non esisteva ed è stato appena creato. Se onCreate()restituisce correttamente (non genera un'eccezione), si presume che il database sia stato creato con il numero di versione richiesto. Come conseguenza, non dovresti prenderti SQLExceptionin onCreate()te stesso.

onUpgrade()viene chiamato solo quando esiste il file di database ma il numero di versione memorizzato è inferiore a quello richiesto nel costruttore. L' onUpgrade()dovrebbe aggiornare lo schema della tabella per la versione richiesta.

Quando si modifica lo schema della tabella in code ( onCreate()), è necessario assicurarsi che il database sia aggiornato. Due approcci principali:

  1. Eliminare il vecchio file di database in modo che onCreate()venga eseguito nuovamente. Questo è spesso preferito in fase di sviluppo in cui si ha il controllo sulle versioni installate e la perdita di dati non è un problema. Alcuni modi per eliminare il file di database:

    • Disinstallare l'applicazione. Utilizzare il gestore applicazione o adb uninstall your.package.namedalla shell.

    • Cancella dati dell'applicazione. Usa il gestore delle applicazioni.

  2. Incrementare la versione del database in modo che onUpgrade()venga invocata. Questo è leggermente più complicato in quanto è necessario più codice.

    • Per gli aggiornamenti dello schema dei tempi di sviluppo in cui la perdita di dati non è un problema, è possibile utilizzare semplicemente execSQL("DROP TABLE IF EXISTS <tablename>")per rimuovere le tabelle esistenti e chiamare onCreate()per ricreare il database.

    • Per le versioni rilasciate, è necessario implementare la migrazione dei dati in onUpgrade()modo che gli utenti non perdano i propri dati.


2
@Laalto // migrazione dei dati in onUpgrade () // Puoi spiegare per favore.
bCliks

2
@bala Non nell'ambito di questa domanda / risposta. Se hai una domanda, sentiti libero di pubblicarla come domanda.
Laalto,

2
@Jaskey Il numero di versione è per il tuo codice, ovvero per quale versione dello schema il codice si aspetta di eseguire. Se il file è più vecchio (rispetto a una versione precedente dell'app), deve essere aggiornato.
laalto,

4
Quindi, ho bisogno di codificare la VERSIONE DB in SQLiteHelper ogni volta che modifico lo schema, in modo che quando la vecchia app viene eseguita e ottenga la connessione db e la trovi vecchia, quindi su Upgrade verrà trorgigerato invece di onCreate, è questo giusto?
Jaskey,

2
Grazie ! Questo ha senso per me. Verifica se ho capito bene. Quindi dobbiamo fare 1. ogni volta che aggiorniamo lo schema, modifica la variabile DB_VERSION (codice fisso). 2. In onUpdate(), controlla ogni versione precedente ed esegui la corretta migrazione dei dati. E poi quando un utente aggiorna la sua app (hanno vecchi file db), onUpgradeverrà attivato e, se l'utente è di nuova installazione, onCreate()viene attivato.
Jaskey,

97

Per aggiungere ulteriori punti mancanti qui, secondo la richiesta di Jaskey

La versione del database è memorizzata nel SQLitefile del database.

la cattura è il costruttore

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

Pertanto, quando il costruttore dell'helper del database viene chiamato con un name(2o parametro), la piattaforma verifica se il database esiste o meno e se il database esiste, ottiene le informazioni sulla versione dall'intestazione del file del database e attiva la richiamata corretta

Come già spiegato nella risposta precedente, se il database con il nome non esiste, si innesca onCreate.

Di seguito la spiegazione spiega il onUpgradecaso con un esempio.

Supponiamo che la tua prima versione dell'applicazione abbia avuto DatabaseHelper(estendendo SQLiteOpenHelper) la versione di passaggio del costruttore come 1e quindi hai fornito un'applicazione aggiornata con il nuovo codice sorgente con la versione passata come 2, quindi automaticamente quando DatabaseHelperviene costruita, la piattaforma si innesca onUpgradevedendo il file già esistente, ma la versione è inferiore alla versione corrente che hai superato.

Ora supponiamo che stai pianificando di fornire una terza versione dell'applicazione con la versione db come 3(la versione db viene aumentata solo quando lo schema del database deve essere modificato). In tali aggiornamenti incrementali, è necessario scrivere la logica di aggiornamento da ciascuna versione in modo incrementale per un codice gestibile migliore

Esempio di pseudo codice di seguito:

@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);
  }
}

Si noti la breakdichiarazione mancante nel caso 1e 2. Questo è ciò che intendo per aggiornamento incrementale.

Dire se la vecchia versione è 2e nuove versioni 4, allora la logica sarà l'aggiornamento del database da 2a 3e poi a4

Se vecchia versione è 3e nuove versioni 4, sarà solo eseguire la logica di aggiornamento per 3a4


1
Penso che tu voglia invece il tuo switch (newVersion) essere switch (oldVersion). Puoi anche verificare che newVersion sia 4 (e non 5, o 3; poiché la tua logica presuppone che la nuova versione dovrebbe essere 4) .Se lo è, se la vecchia versione è 2 e la nuova versione è 5, dovrai toccare il caso 4: e aggiornare da 3 a 4 (che probabilmente non dovrebbe essere previsto comportamento).
joe p

giusto - errore di battitura .. ma se la nuova versione è 5 -> allora lancerà sempre IllegalStateException e lo sviluppatore lo risolverà aggiungendo il caso 5 ..
Aun

1
Cosa succede se l'utente aggiorna la sua app solo dalla versione 2 alla 3? Anche in quel caso, verranno eseguiti tutti i casi fino al caso 4.
Paramvir Singh,

6
L'utente @param non può farlo. Può aggiornare solo 2 all'ultimo (qui 4).
Habeeb Perwad,

20

onCreate()

  1. Quando creiamo DataBase per la prima volta (ovvero il database non esiste), onCreate()creiamo un database con la versione che viene passata SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()Il metodo sta creando le tabelle che hai definito ed eseguendo qualsiasi altro codice che hai scritto. Tuttavia, questo metodo verrà chiamato solo se il file SQLite manca nella directory dei dati della tua app ( /data/data/your.apps.classpath/databases).

  3. Questo metodo non verrà chiamato se hai modificato il codice e riavviato nell'emulatore. Se si desidera onCreate()eseguire è necessario utilizzare adb per eliminare il file di database SQLite.

onUpgrade()

  1. SQLiteOpenHelper dovrebbe chiamare il super costruttore.
  2. Il onUpgrade()metodo verrà chiamato solo quando il numero intero della versione è più grande della versione corrente in esecuzione nell'app.
  3. Se si desidera onUpgrade()chiamare il metodo, è necessario aumentare il numero di versione nel codice.

1
Potresti per favore elaborare di più la tua risposta aggiungendo un po 'più di descrizione della soluzione che offri?
Abarisone,

10

Forse sono in ritardo, ma vorrei condividere la mia breve e dolce risposta. Controlla la risposta per lo stesso problema. Ti aiuterà sicuramente. Niente più specifiche profonde.

Se sei sicuro della sintassi per la creazione di una tabella, ciò può accadere quando aggiungi una nuova colonna nella stessa tabella, per quello ...

1) Disinstallare dal dispositivo ed eseguirlo nuovamente.

O

2) Impostazione -> app -> ClearData

O

3) Modifica DATABASE_VERSIONnella tua classe "DatabaseHandler" (Se hai aggiunto una nuova colonna, questa verrà aggiornata automaticamente)

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

O

4) Modifica DATABASE_NAMEnella tua classe "DatabaseHandler" (ho riscontrato lo stesso problema. Ma riesco cambiando DATABASE_NAME.)


Ho il mio DB e utilizzo la classe SQLiteAssetHelper. Quindi, ho creato il DB con sql script prima e il db è stato creato. Utilizzando SQLiteAssetHelper non è stato possibile copiare il DB fino alla disinstallazione dell'app dall'emulatore o dal dispositivo, poiché era un db con la stessa versione.
Behzad,

4

Punti da ricordare durante l'estensione SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Questo dovrebbe essere invocato prima riga del costruttore
  2. sovrascrivere onCreatee onUpgrade(se necessario)
  3. onCreateverrà invocato solo quando getWritableDatabase()o getReadableDatabase()viene eseguito. E questo verrà invocato solo una volta quando uno DBNamespecificato nel primo passaggio non è disponibile. È possibile aggiungere la query di creazione tabella sul onCreatemetodo
  4. Ogni volta che desideri aggiungere una nuova tabella, modifica DBversione fai le query nella onUpgradetabella o semplicemente disinstalla, quindi installa l'app.

3

onCreate viene chiamato per la prima volta quando è necessaria la creazione di tabelle. Dobbiamo sovrascrivere questo metodo in cui scriviamo lo script per la creazione di tabelle che viene eseguito da SQLiteDatabase. metodo execSQL. Dopo l'esecuzione nella prima distribuzione, questo metodo non verrà chiamato in avanti.

onUpgrade Questo metodo viene chiamato quando viene aggiornata la versione del database. Supponiamo che per la prima volta la distribuzione, la versione del database fosse 1 e nella seconda distribuzione ci siano stati cambiamenti nella struttura del database come l'aggiunta di una colonna aggiuntiva nella tabella. Supponiamo che la versione del database sia 2 ora.


2

È possibile creare database e tabelle come

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);
  }
}

Nota: se si desidera creare un'altra tabella o aggiungere colonne o nessuna tabella di questo tipo, è sufficiente aumentare la VERSIONE


2

Il database Sqlite ha la precedenza su due metodi

1) onCreate (): questo metodo è stato richiamato una sola volta al primo avvio dell'applicazione. Quindi ha chiamato solo una volta

2) onUpgrade () Questo metodo viene chiamato quando cambiamo la versione del database, quindi questo metodo viene invocato. Viene utilizzato per modificare la struttura della tabella come l'aggiunta di una nuova colonna dopo aver creato lo schema DB


1

nessuna tabella di questo tipo viene trovata principalmente quando non hai aperto la SQLiteOpenHelperclasse con getwritabledata()e prima di ciò devi anche chiamare make constructor con nome database e versione. E OnUpgradeviene chiamato ogni volta che c'è un valore di aggiornamento nel numero di versione fornito in SQLiteOpenHelperclasse.

Di seguito è riportato lo snippet di codice (nessuna colonna trovata potrebbe essere dovuta all'incantesimo nel nome della colonna):

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

Se si dimentica di fornire una stringa "name" come secondo argomento al costruttore, crea un database "in memoria" che viene cancellato quando si chiude l'app.


0

Disinstallare l'applicazione dall'emulatore o dal dispositivo. Esegui di nuovo l'app. (OnCreate () non viene eseguito quando il database esiste già)


0

Il nome del database deve terminare con .db anche le stringhe di query devono avere un terminatore (;)


0

Ricontrolla la tua query nella tua classe DatabaseHandler / DatabaseManager (che hai mai preso)


0

Nel mio caso ottengo elementi da file XML con <string-array>, dove conservo <item>i messaggi. In questi <item>s tengo stringhe SQL e applico uno per uno con databaseBuilder.addMigrations(migration). Ho fatto un errore, ho dimenticato di aggiungere \prima del preventivo e ho ottenuto l'eccezione:

android.database.sqlite.SQLiteException: nessuna di queste colonne: some_value (codice 1 SQLITE_ERROR):, durante la compilazione: INSERT INTO table_name (id, name) VALUES (1, some_value)

Quindi, questa è una variante giusta:

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

-2

Il metodo Sqliteopenhelper prevede metodi di creazione e aggiornamento, create viene utilizzato quando viene creata una tabella per la prima volta e il metodo di aggiornamento viene chiamato ogni volta che viene modificato il numero di colonne della tabella.


Il metodo onUpgrade viene chiamato quando aumenta la versione del database, non quando viene modificato il numero di colonne. Rif: developer.android.com/reference/android/database/sqlite/… , int, int)
Roger Huang
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.