tutorial querybuilder implement devopenhelper android orm greendao

android - querybuilder - Actualización del esquema de greenDao



orm android 2018 (3)

Finalmente tuve tiempo de profundizar en esto y me di cuenta de que es bastante fácil agregar una nueva tabla mientras se conservan los datos en tablas antiguas.

DESCARGO DE RESPONSABILIDAD : Aunque me doy cuenta de que esta implementación es específica para mi escenario, creo que es útil para alguien como yo que ha utilizado una herramienta ORM de Android (greenDao) exclusivamente para tratar SQLite en Android. Entiendo que esto es bastante común para aquellos de ustedes que han escrito sus propias consultas de creación de tablas desde el principio, pero para alguien que ha estado protegido de las entrañas de usar una base de datos SQLite con Android, creo que este ejemplo será útil.

RESPUESTA: Puede modificar la clase interna DevOpenHelper o crear su propia clase. Elegí editar DevOpenHelper por el momento para mantener mi ejemplo simple. Sin embargo, tenga en cuenta que si regenera sus clases de greendao, se sobrescribirá DevOpenHelper. Sería una mejor idea crear tu propia clase como "MyOpenHelper" y usarla en su lugar.

Antes de mis cambios, DevOpenHelper.onUpgrade se veía así:

@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); dropAllTables(db, true); onCreate(db); }

En lugar de eliminar todas las tablas, eche un vistazo al método createAllTables generado automáticamente por GreenDao.

Vuelva a escribir onUpgrade para comprobar si la "versión antigua" es la que desea actualizar, luego solo llame a los métodos createTable para tablas "nuevas". Aquí es como se ve mi método onUpgrade ahora:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + //Going from older schema to new schema if(oldVersion == 3 && newVersion == 4) { boolean ifNotExists = false; //Leave old tables alone and only create ones that didn''t exist //in the previous schema NewTable1Dao.createTable(db, ifNotExists); NewTable2Dao.createTable(db, ifNotExists); NewTable3Dao.createTable(db, ifNotExists); NewTable4Dao.createTable(db, ifNotExists); } else { dropAllTables(db, true); onCreate(db); } }

Agregar una nueva columna sería similar, excepto que tendría que escribir algo de SQL o echar un vistazo a las sentencias de creación SQL generadas automáticamente desde GreenDao y aprovecharlas.

Para agregar una nueva columna (NEW_COLUMN, suponiendo que es un tipo INTEGER) a una tabla existente (EXISTING_TABLE), haga lo siguiente:

db.execSQL("ALTER TABLE ''EXISTING_TABLE'' ADD ''NEW_COLUMN'' INTEGER");

Para mí en este momento, todo lo que tenía que hacer era agregar nuevas Tablas, así que esto terminó siendo bastante sencillo. Esperemos que alguien más lo encuentre útil.

He visto otra pregunta sobre la actualización / migración de esquemas usando dao verde ( here )

Hay muchos enlaces en esa respuesta para un buen patrón para usar al hacer actualizaciones de esquema, sin embargo, no hay ejemplos de lo que realmente hace con sus datos para migrarlos correctamente y tengo problemas para encontrar algo.

En mi caso, mi migración es increíblemente sencilla: no deseo transformar ningún dato existente, simplemente necesito agregar algunas tablas nuevas a mi esquema, que sospecho que es una situación bastante común.

¿Cuál es la forma más fácil de agregar nuevas tablas a su esquema sin eliminar los datos que sus usuarios ya han guardado? Un ejemplo específico sería muy apreciado.

Sería increíble si GreenDao proporcionara una clase similar a DevOpenHelper que simplemente agregaría nuevas tablas / columnas que no existían previamente en el esquema sin eliminar primero las pestañas / datos existentes.


Hice un enfoque ligeramente diferente para manejar las actualizaciones automáticamente sin importar de dónde venga el usuario anterior. Primero creé una clase que implementa el método onUpgrade en una base de datos SQL

public abstract class AbstractMigratorHelper { public abstract void onUpgrade(SQLiteDatabase db); }

De esta clase heredaremos todos los ayudantes de migradores que declararé después

Voy a escribir un ejemplo de uno de ellos.

public class DBMigrationHelper5 extends AbstractMigratorHelper { /* Upgrade from DB schema x to schema x+1 */ public void onUpgrade(SQLiteDatabase db) { //Example sql statement db.execSQL("ALTER TABLE user ADD COLUMN USERNAME TEXT"); } }

Después de esto, debe implementar la lógica en la clase a la que realmente se llama en la actualización, donde deberá eliminar el DevOpenHelper anterior para obtener uno personalizado que podría tener este aspecto

public static class UpgradeHelper extends OpenHelper { public UpgradeHelper(Context context, String name, CursorFactory factory) { super(context, name, factory); } /** * Here is where the calls to upgrade are executed */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { /* i represent the version where the user is now and the class named with this number implies that is upgrading from i to i++ schema */ for (int i = oldVersion; i < newVersion; i++) { try { /* New instance of the class that migrates from i version to i++ version named DBMigratorHelper{version that the db has on this moment} */ AbstractMigratorHelper migratorHelper = (AbstractMigratorHelper) Class.forName("com.nameofyourpackage.persistence.MigrationHelpers.DBMigrationHelper" + i).newInstance(); if (migratorHelper != null) { /* Upgrade de db */ migratorHelper.onUpgrade(db); } } catch (ClassNotFoundException | ClassCastException | IllegalAccessException | InstantiationException e) { Log.e(TAG, "Could not migrate from schema from schema: " + i + " to " + i++); /* If something fail prevent the DB to be updated to future version if the previous version has not been upgraded successfully */ break; } } } }

Entonces, si es cuidadoso al nombrar a sus Ayudantes de migración (es decir, MigrationHelper5 realiza la migración del esquema 5 al esquema 6), puede implementar esta lógica y luego en cada clase MigratorHelper solo implementa la llamada execSQL con todo el código SQL que necesita implementar.

Finalmente, una observación más, si está trabajando con proguard, es posible que el método encontrar nombre por clase no funcione, ya que los nombres de clase se cambian al ofuscar el código. Es posible que desee considerar agregar una excepción en el archivo de configuración de proguard (proguard-rules.pro) para excluir cualquier clase que se extienda desde AbstractMigratorHelper

# Avoid errors when upgrading database migrators -keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper


Lo hago de una manera ligeramente diferente.

Agrego mis nuevas clases de @DatabaseTable y cualquier @DatabaseFields a las clases existentes de @DatabaseTable y ejecuto DatabaseConfigUtil.

Luego agregaré un nuevo método a mi clase DatabaseUpgrader y modificaré mi DatabaseHelper, cambiando el valor DATABASE_VERSION y el método onUpdate

public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final int DATABASE_VERSION = 3; @Override public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) { if (newVersion > oldVersion) { switch (oldVersion) { case 1: DatabaseUpdater.from1to2(connectionSource); DatabaseUpdater.from2to3(connectionSource); break; case 2: DatabaseUpdater.from2to3(connectionSource); break; default: onCreate(db); } } } public static DatabaseHelper getInstance() { return DatabaseHelper.mHelper; } public static void setInstance(Context context) { DatabaseHelper.mHelper = new DatabaseHelper(context); } … }

Y luego en la clase DatabaseUpdater

public class DatabaseUpdater { private static final String TAG = "DatabaseHelper"; public static void from1to2(ConnectionSource connectionSource) { try { DatabaseHelper helper = DatabaseHelper.getInstance(); //Example add a table TableUtils.createTable(connectionSource, AnotherEntity.class); } catch (SQLException e) { Log.e(TAG, "Error upgrading database to v2: ", e); } catch (java.sql.SQLException e) { e.printStackTrace(); } } public static void from2to3(ConnectionSource connectionSource) { try { DatabaseHelper helper = DatabaseHelper.getInstance(); //Example add a field to a table RuntimeExceptionDao<MyEntity, Integer> myDao = helper.getMyDao(); diaryDao.executeRaw("ALTER TABLE myEntity ADD firstNewField"); diaryDao.executeRaw("ALTER TABLE myEntity ADD anotherNewField"); } catch (SQLException e) { Log.e(TAG, "Error upgrading database to v3: ", e); } } }