Confusión: ¿Cómo se comporta SQLiteOpenHelper onUpgrade ()? ¿Y junto con la importación de una copia de seguridad de la base de datos anterior?

supongamos que tengo una tabla de base de datos test_table con 2 columnas y un script de creación correspondiente en SQLiteOpenHelper:

DB_VERSION = 1: public void onCreate(SQLiteDatabase db) { db.execSql("CREATE table test_table (COL_A, COL_B); } 

Esta es la versión inicial de la aplicación 1, que se publica en Play Store.

Después de un tiempo, hay una actualización de la aplicación y la base de datos utilizada. Supongo que la clase SQLiteOpenHelper debe adaptarse de esta manera:

 DB_VERSION = 2: public void onCreate(SQLiteDatabase db) { db.execSql("CREATE table test_table (COL_A, COL_B, COL_C)"); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSql("ALTER TABLE test_table ADD Column COL_C"); } 

Después de un tiempo, otra actualización de la aplicación:

 DB_VERSION = 3: public void onCreate(SQLiteDatabase db) { db.execSql("CREATE table test_table (COL_A, COL_B, COL_C, COL_D)"); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSql("ALTER TABLE test_table ADD Column COL_D"); } 

-> Aquí es donde necesito consejos. Si el usuario instala la aplicación versión 1, tiene las columnas A y B. Si luego actualiza a la versión 2, onUpgrade activa y agrega una columna C. Los nuevos usuarios que instalan desde cero obtienen las 3 columnas mediante la instrucción create. Si el usuario luego actualiza a la versión 3, onUpgrade vuelve a activarse y se agrega una columna D. Pero ¿QUÉ PASA SI el usuario instala la aplicación versión 1, luego omite la actualización de la versión 2 y actualiza la versión 3? Entonces él se habría perdido el

 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSql("ALTER TABLE test_table ADD Column COL_C"); } 

parte y solo

 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSql("ALTER TABLE test_table ADD Column COL_D"); } 

se llamaría, lo que lleva a una tabla test_table (COL_A, COL_B, COL_D) ??

¿Cuál es la forma correcta de manejar las actualizaciones de la base de datos de una aplicación en vivo, para que el usuario no pierda sus datos? ¿Tiene que verificar todas las versiones posibles (antiguas) en el método onUpgrade () y ejecutar diferentes sentencias alter table basadas en esa versión?

Lo estoy preguntando porque en mi aplicación, el usuario tiene la posibilidad de exportar e importar los datos, que no es más que exportar: copiar toda la base de datos e importarla: reemplace la base de datos de la aplicación con la base de datos de copia de respaldo.

¿Qué sucede si el usuario tiene la aplicación versión 1, exporta la base de datos, actualiza la aplicación (nueva estructura de la base de datos) e importa la copia de seguridad de la versión 1 anterior? -> ¿Cómo se comportará SQLiteOpenHelper? -> ¿Cuál es la forma correcta de manejar las actualizaciones de db junto con la funcionalidad de importación / exportación?

¿Cuál es la forma correcta de manejar las actualizaciones de la base de datos de una aplicación en vivo, para que el usuario no pierda sus datos? ¿Tiene que verificar todas las versiones posibles (antiguas) en el método onUpgrade () y ejecutar diferentes sentencias alter table basadas en esa versión?

En general, sí.

Un enfoque común para esto es hacer actualizaciones en pares:

 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion<2) { // do upgrade from 1 to 2 } if (oldVersion<3) { // do upgrade from 2 to 3, which will also cover 1->3, // since you just upgraded 1->2 } // and so on } 

Esto equivale aproximadamente a las migraciones de Rails, por ejemplo.

¿Qué sucede si el usuario tiene la aplicación versión 1, exporta la base de datos, actualiza la aplicación (nueva estructura de la base de datos) e importa la copia de seguridad de la versión 1 anterior? -> ¿Cómo se comportará SQLiteOpenHelper?

Si al “copiar toda la base de datos”, significa literalmente una copia de archivo completo del archivo de base de datos SQLite, cuando SQLiteOpenHelper va a abrir la copia de seguridad restaurada, la base de datos tendrá la versión de esquema anterior y pasará a onUpgrade() como normal.

¿Cuál es la forma correcta de manejar las actualizaciones de db junto con la funcionalidad de importación / exportación?

Sospecho que la respuesta es: haga su copia de seguridad copiando el archivo completo, o arregle también hacer una copia de seguridad y restaurar la versión del esquema, que puede obtener llamando a getVersion() en un objeto SQLiteDatabase . Dicho esto, no he tratado mucho este escenario, y puede que haya más problemas en los que no estoy pensando.

a continuación el código de psuedo muestra una actualización increamental

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

Me refiero a la actualización incremental. Observe la statement de ruptura faltante en el caso 2 y 3.

decir si la versión anterior es 2 y la versión nueva es 4, entonces la lógica actualizará la base de datos de 2 a 3 y luego a 4

si la versión anterior es 3 y la nueva versión es 4, solo ejecutará la lógica de actualización de 3 a 4

sigue agregando nuevos casos para cada nueva actualización de versión de base de datos que hará los cambios incrementales

sospecho que también puedes crear una nueva tabla con todas las columnas que necesitas

CREATE TABLE new_test_table (COL_A, COL_B, COL_C,COL_D);

copiar los datos de la tabla anterior a la nueva

INSERT INTO new_test_table SELECT * FROM test_table;

soltar la tabla anterior DROP TABLE test_table;

y renombrar la nueva tabla

ALTER TABLE new_test_table RENAME TO test_table;

así que en resumen

 public void onUpgrade(SQLiteDatabase db,int OldVersion,int NewVersion){ db.execSQL("CREATE TABLE new_test_table (COL_A, COL_B, COL_C,COL_D);"+ "INSERT INTO new_test_table SELECT * FROM test_table;"+ "DROP TABLE test_table;"+ "ALTER TABLE new_test_table RENAME TO test_table;");" } 

de esa manera no tienes que preocuparte por dataloss o cambios incrementales

Android-Database-Upgrade-Tutorial muestra la guía completa de cómo maneja la actualización del esquema de la base de datos de su aplicación al tiempo que lanza nuevas versiones de la aplicación.

El tutorial consiste en una aplicación que tiene 4 versiones, cada versión contiene diferentes números de columnas, Diferentes versiones de la aplicación

Estos son los diferentes escenarios que uno puede enfrentar Diferentes escenarios

Creo que es demasiado tarde para responder a esta pregunta, pero puede ayudar a otros.

  DB_VERSION = 1: public void onCreate(SQLiteDatabase db) { db.execSql("CREATE table test_table (COL_A, COL_B, COL_C, COL_D, COL_E); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: db.execSql("ALTER TABLE test_table ADD Column COL_C"); db.execSql("ALTER TABLE test_table ADD Column COL_D"); db.execSql("ALTER TABLE test_table ADD Column COL_E"); break; case 2: db.execSql("ALTER TABLE test_table ADD Column COL_D"); db.execSql("ALTER TABLE test_table ADD Column COL_E"); break; case 3: db.execSql("ALTER TABLE test_table ADD Column COL_E"); break; and so on... } 

Si el usuario instala la aplicación por primera vez, obtendrá todas las columnas de onCreate

Si la versión anterior de la base de datos 2, entonces el caso 2 agrega la columna C y D.

Si la versión anterior de la base de datos 3, entonces el caso 3 solo agrega la columna E

De esa manera no hay confusión sobre la versión de la base de datos.