¿Cuándo se ejecuta SQLiteOpenHelper onCreate () / onUpgrade ()?

293

He creado mis tablas en mi SQLiteOpenHelper onCreate()pero recibo

SQLiteException: no such table

o

SQLiteException: no such column

errores ¿Por qué?

NOTA:

(Este es el resumen amalgamado de decenas de preguntas similares cada semana. Intentando proporcionar una pregunta / respuesta wiki comunitaria "canónica" aquí para que todas esas preguntas puedan ser dirigidas a una buena referencia).

laalto
fuente
12
@Ndupza Este no es un problema real mío, solo me cansé de escribir la misma respuesta / comentario por enésima vez.
laalto

Respuestas:

352

SQLiteOpenHelper onCreate()y las onUpgrade()devoluciones de llamada se invocan cuando la base de datos se abre realmente, por ejemplo, mediante una llamada a getWritableDatabase(). La base de datos no se abre cuando se crea el objeto auxiliar de la base de datos.

SQLiteOpenHelperversiones de los archivos de la base de datos. El número de versión es el intargumento pasado al constructor . En el archivo de la base de datos, el número de versión se almacena en PRAGMA user_version.

onCreate()solo se ejecuta cuando el archivo de la base de datos no existía y se acaba de crear. Si onCreate()regresa con éxito (no arroja una excepción), se supone que la base de datos se crea con el número de versión solicitado. Como una implicación, no debes atraparte SQLExceptionen onCreate()ti mismo.

onUpgrade()solo se llama cuando existe el archivo de base de datos pero el número de versión almacenado es inferior al solicitado en el constructor. El onUpgrade()debe actualizar el esquema de la tabla a la versión solicitada.

Al cambiar el esquema de la tabla en el código ( onCreate()), debe asegurarse de que la base de datos esté actualizada. Dos enfoques principales:

  1. Elimine el antiguo archivo de base de datos para que onCreate()se ejecute nuevamente. Esto suele preferirse en el momento del desarrollo, donde tiene control sobre las versiones instaladas y la pérdida de datos no es un problema. Algunas formas de eliminar el archivo de base de datos:

    • Desinstala la aplicación. Use el administrador de aplicaciones o adb uninstall your.package.namedesde el shell.

    • Borrar datos de la aplicación. Utiliza el administrador de aplicaciones.

  2. Incremente la versión de la base de datos para que onUpgrade()se invoque. Esto es un poco más complicado ya que se necesita más código.

    • Para las actualizaciones del esquema de tiempo de desarrollo donde la pérdida de datos no es un problema, solo puede usar execSQL("DROP TABLE IF EXISTS <tablename>")para eliminar sus tablas existentes y llamar onCreate()para volver a crear la base de datos.

    • Para las versiones lanzadas, debe implementar la migración de datos onUpgrade()para que sus usuarios no pierdan sus datos.

laalto
fuente
2
@Laalto // migración de datos en onUpgrade () // ¿Puede explicar esto?
bCliks
2
@bala No está dentro del alcance de esta pregunta / respuesta. Si tiene una pregunta, no dude en publicarla como una pregunta.
laalto
2
@Jaskey El número de versión es para su código, es decir, con qué versión de esquema se ejecuta el código. Si el archivo es anterior (de una versión anterior de su aplicación), debe actualizarse.
laalto
44
Por lo tanto, necesito codificar la VERSIÓN DB en el SQLiteHelper cada vez que modifique el esquema, de modo que cuando la aplicación anterior se ejecute y obtenga la conexión db y encuentre que es antigua, y luego onUpgrade se activará en lugar de onCreate, es esto ¿Derecha?
Jaskey
2
Gracias ! Esto tiene sentido para mí. Verifique si entiendo bien. Por lo tanto, debemos hacer 1. cada vez que actualizamos el esquema, modifiquemos la variable DB_VERSION (código duro). 2. En onUpdate(), verifique cada versión anterior y realice la migración de datos adecuada. Y luego, cuando un usuario actualiza su aplicación (tiene archivos db antiguos), se onUpgradeactivará y, si el usuario está recién instalado, onCreate()se activará.
Jaskey
97

Para agregar más puntos faltantes aquí, según la solicitud de Jaskey

La versión de la base de datos se almacena en el SQLitearchivo de la base de datos.

catch es el constructor

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

Entonces, cuando se llama al constructor auxiliar de la base de datos con un name(segundo parámetro), la plataforma verifica si la base de datos existe o no y si la base de datos existe, obtiene la información de la versión del encabezado del archivo de la base de datos y activa la devolución de llamada correcta

Como ya se explicó en la respuesta anterior, si la base de datos con el nombre no existe, se dispara onCreate.

La explicación a continuación explica el onUpgradecaso con un ejemplo.

Digamos, su primera versión de la aplicación tenía la versión DatabaseHelper(que se extendía SQLiteOpenHelper) con el constructor que pasaba la versión 1y luego proporcionó una aplicación actualizada con el nuevo código fuente que tenía la versión aprobada 2, y automáticamente cuando DatabaseHelperse construye, la plataforma se dispara onUpgradeal ver que el archivo ya existe, pero la versión es inferior a la versión actual que ha pasado.

Ahora supongamos que planea dar una tercera versión de la aplicación con la versión db como 3(la versión db se incrementa solo cuando se va a modificar el esquema de la base de datos). En tales actualizaciones incrementales, debe escribir la lógica de actualización de cada versión de forma incremental para obtener un mejor código mantenible

Ejemplo de pseudocódigo a continuación:

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

Observe la breakdeclaración que falta en el caso 1y 2. Esto es lo que quiero decir con actualización incremental.

Decir si la versión antigua es 2y nuevas versiones 4, entonces la lógica se actualice la base de datos a partir 2de 3y después de4

Si la versión antigua es 3y nuevas versiones 4, se acaba de ejecutar la lógica de actualización para 3a4

Aun
fuente
1
Creo que quieres que tu switch (newVersion) sea switch (oldVersion) en su lugar. También puede verificar que newVersion sea 4 (y no 5, o 3; porque su lógica asume que la nueva versión debería ser 4). Tal como está, si la versión anterior es 2 y la nueva versión es 5, golpee el caso 4: y actualice de 3 a 4 (que probablemente no debería ser un comportamiento esperado).
Joe p
right - typo .. pero si la nueva versión es 5 -> entonces siempre arrojará IllegalStateException y el desarrollador lo corregirá agregando el caso 5 ..
Aun
1
¿Qué sucede si el usuario solo actualiza su aplicación de la versión 2 a la 3? En ese caso también, se ejecutarán todos los casos hasta el caso 4.
Paramvir Singh
66
El usuario @param no puede hacer eso. Puede actualizar 2 a la última (aquí 4) solamente.
Habeeb Perwad
20

onCreate()

  1. Cuando creamos DataBase por primera vez (es decir, la base de datos no existe) onCreate()crea una base de datos con la versión que se pasa SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

  2. onCreate()El método es crear las tablas que ha definido y ejecutar cualquier otro código que haya escrito. Sin embargo, este método solo se llamará si falta el archivo SQLite en el directorio de datos de su aplicación ( /data/data/your.apps.classpath/databases).

  3. No se llamará a este método si ha cambiado su código y se ha relanzado en el emulador. Si desea onCreate()ejecutar, debe usar adb para eliminar el archivo de base de datos SQLite.

onUpgrade()

  1. SQLiteOpenHelper debería llamar al súper constructor.
  2. El onUpgrade()método sólo será llamada cuando el número entero versión es mayor que la versión actual que se ejecuta en la aplicación.
  3. Si desea onUpgrade()que se llame al método, debe incrementar el número de versión en su código.
jeet parmar
fuente
1
¿Podría por favor elaborar más su respuesta agregando un poco más de descripción sobre la solución que proporciona?
abarisone
10

Puede que sea demasiado tarde, pero me gustaría compartir mi respuesta breve y dulce. Por favor, marque Respuesta para un mismo problema. Definitivamente te ayudará. No más especificaciones profundas.

Si está seguro de la sintaxis para crear una tabla, entonces puede suceder cuando agrega una nueva columna en su misma tabla, para eso ...

1) Desinstale de su dispositivo y ejecútelo nuevamente.

O

2) Configuración -> aplicación -> ClearData

O

3) Cambie DATABASE_VERSIONen su clase "DatabaseHandler" (si ha agregado una nueva columna, se actualizará automáticamente)

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

O

4) Cambie DATABASE_NAMEen su clase "DatabaseHandler" (me enfrenté al mismo problema. Pero tengo éxito al cambiar DATABASE_NAME).

shital
fuente
Tengo mi propia base de datos y estoy usando la clase SQLiteAssetHelper. Entonces, creé el DB por el script sql antes y se creó el db. Al usar SQLiteAssetHelper, no pudo copiar la base de datos hasta desinstalar la aplicación del emulador o dispositivo, porque era un DB con la misma versión.
Behzad
4

Puntos para recordar al extender SQLiteOpenHelper

  1. super(context, DBName, null, DBversion); - Se debe invocar la primera línea del constructor.
  2. anular onCreatey onUpgrade(si es necesario)
  3. onCreatese invocará solo cuando getWritableDatabase()o getReadableDatabase()se ejecute. Y esto solo se invocará una vez cuando un DBNameespecificado en el primer paso no esté disponible. Puede agregar crear tabla de consulta en el onCreatemétodo
  4. Cada vez que desee agregar una nueva tabla, simplemente cambie DBversiony realice las consultas en la onUpgradetabla o simplemente desinstale e instale la aplicación.
JibinNajeeb
fuente
3

Se llama a onCreate por primera vez cuando se necesita la creación de tablas. Necesitamos anular este método donde escribimos el script para la creación de la tabla que es ejecutado por SQLiteDatabase. Método execSQL. Después de ejecutar la primera implementación, este método no se llamará en adelante.

onUpgrade Este método se llama cuando se actualiza la versión de la base de datos. Supongamos que, por primera vez, la versión de la base de datos fue 1 y en la segunda implementación hubo un cambio en la estructura de la base de datos, como agregar una columna adicional en la tabla. Supongamos que la versión de la base de datos es 2 ahora.

Faxriddin Abdullayev
fuente
2

Puede crear bases de datos y tablas como

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: si desea crear otra tabla o agregar columnas o ninguna, simplemente incremente la VERSIÓN

Enamul Haque
fuente
2

La base de datos SQLite anula dos métodos

1) onCreate (): este método se invoca solo una vez cuando la aplicación se inicia por primera vez. Entonces llamó solo una vez

2) onUpgrade () Este método se llama cuando cambiamos la versión de la base de datos, luego se invoca este método. Se utiliza para alterar la estructura de la tabla como agregar una nueva columna después de crear el esquema de base de datos

sushant suryawanshi
fuente
1

no se encuentra dicha tabla principalmente cuando no ha abierto la SQLiteOpenHelperclase con getwritabledata()y antes de esto también debe llamar a make constructor con databasename & version. Y OnUpgradese llama cada vez que hay un valor de actualización en el número de versión dado en la SQLiteOpenHelperclase.

A continuación se muestra el fragmento de código (tal columna no encontrada puede deberse a la ortografía en el nombre de la columna):

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

}
Bharat Lalwani
fuente
1

Si olvida proporcionar una cadena de "nombre" como segundo argumento para el constructor, crea una base de datos "en memoria" que se borra al cerrar la aplicación.

phreakhead
fuente
0

Desinstale su aplicación del emulador o dispositivo. Ejecute la aplicación nuevamente. (OnCreate () no se ejecuta cuando la base de datos ya existe)

Nand Gopal
fuente
0

El nombre de su base de datos debe terminar con .db y sus cadenas de consulta deben tener un terminador (;)

Omer Haqqani
fuente
0

Vuelva a verificar su consulta en su clase DatabaseHandler / DatabaseManager (cualquiera que haya tomado)

venu
fuente
0

En mi caso, obtengo elementos del archivo XML con <string-array>, donde almaceno <item>s. En estos <item>s sostengo cadenas SQL y aplico una por una con databaseBuilder.addMigrations(migration). Cometí un error, olvidé agregar \antes de la cita y obtuve la excepción:

android.database.sqlite.SQLiteException: no existe esa columna: some_value (code 1 SQLITE_ERROR):, mientras compila: INSERT INTO table_name (id, name) VALUES (1, some_value)

Entonces, esta es una variante correcta:

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

El método de Sqliteopenhelper tiene métodos para crear y actualizar, crear se usa cuando se crea una tabla por primera vez y se llamará al método de actualización cada vez que se cambie el número de columna de la tabla.

Vishwa Pratap
fuente
Se llama al método onUpgrade cuando aumenta la versión de la base de datos, no cuando se cambia el número de columna. Ref: developer.android.com/reference/android/database/sqlite/… , int, int)
Roger Huang