tutorial interfaz grafica espaƱol ejemplos componentes clase java android database-migration android-room

interfaz - java jframe tutorial pdf



MigraciĆ³n de la base de datos de la sala si solo se agrega una nueva tabla (6)

No supongamos que tengo una base de datos simple de Room:

@Database(entities = {User.class}, version = 1) abstract class AppDatabase extends RoomDatabase { public abstract Dao getDao(); }

Ahora, estoy agregando una nueva entidad: Pet and bumping version to 2:

@Database(entities = {User.class, Pet.class}, version = 2) abstract class AppDatabase extends RoomDatabase { public abstract Dao getDao(); }

Por supuesto, Room genera una excepción: java.lang.IllegalStateException: A migration from 1 to 2 is necessary.

Suponiendo que no he cambiado User clase de User (por lo que todos los datos están seguros), tengo que proporcionar la migración que solo crea una nueva tabla. Entonces, estoy buscando clases generadas por Room, buscando consultas generadas para crear mi nueva tabla, copiando y pegando en la migración:

final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull final SupportSQLiteDatabase database) { database.execSQL("CREATE TABLE IF NOT EXISTS `Pet` (`name` TEXT NOT NULL, PRIMARY KEY(`name`))"); } };

Sin embargo, me parece inconveniente hacerlo manualmente. ¿Hay alguna manera de decirle a Room? No estoy tocando ninguna de las tablas existentes, por lo que los datos están seguros. ¿Por favor crear migración para mí?


En este caso, no necesita hacer una migración, puede llamar a .fallbackToDestructiveMigration () cuando crea una instancia de base de datos.

Ejemplo:

instance = Room.databaseBuilder(context, AppDatabase.class, "database name").fallbackToDestructiveMigration().build();

Y no olvide cambiar la versión de la base de datos.


Lo sentimos, Room no admite la creación automática de tablas sin pérdida de datos.

Es obligatorio escribir la migración. De lo contrario, borrará todos los datos y creará la nueva estructura de la tabla.


Puede agregar el siguiente comando gradle a su configuración predeterminada en su app.gradle:

javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } }

Cuando ejecute esto, compilará una lista de nombres de tablas con sus correspondientes declaraciones CREATE TABLE desde las cuales puede copiar y pegar en sus objetos de migración. Puede que tenga que cambiar los nombres de la tabla.

Por ejemplo, esto es de mi esquema generado:

"tableName": "assets", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `base` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`asset_id`))"

Y así copio, pego la instrucción createSql y cambio el ''$ {TABLE_NAME}'' a ''activos'' el nombre de la tabla, y listo.


Puedes hacerlo de esta manera

@Database(entities = {User.class, Pet.class}, version = 2) abstract class AppDatabase extends RoomDatabase { public abstract Dao getDao(); public abstract Dao getPetDao(); }

El resto será el mismo que ha mencionado anteriormente.

db = Room.databaseBuilder(this, AppDatabase::class.java, "your_db") .addMigrations(MIGRATION_1_2).build()

Referencia - Para más


Tal vez en este caso (si solo ha creado una nueva tabla sin cambiar otras), ¿puede hacer esto sin crear ninguna migración?


La sala NO tiene un buen sistema de migración, al menos hasta 2.1.0-alpha03 .

Se espera que tenga un mejor sistema de migración en 2.2.0

Entonces, hasta que tengamos un mejor sistema de migración, hay algunas soluciones para tener migraciones fáciles en la sala.

Como no existe un método como @Database(createNewTables = true) o MigrationSystem.createTable(User::class) , que debería haber uno u otro, la única forma posible es ejecutar

CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))

dentro de su método de migrate .

val MIGRATION_1_2 = object : Migration(1, 2){ override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))") } }

Para superar el script SQL , tienes 4 formas

1. Escribe por ti mismo

Básicamente, debe escribir el script anterior que coincidirá con el script que genera Room. De esta manera es posible, no factible. (Considere que tiene 50 campos)

2. Esquema de exportación

Si incluye exportSchema = true dentro de su anotación @Database , Room generará un esquema de base de datos dentro de / esquemas de su carpeta de proyecto. El uso es

@Database(entities = [User::class], version = 2, exportSchema = true) abstract class AppDatabase : RoomDatabase { //... }

Asegúrese de haber incluido las líneas siguientes en build.grade de su módulo de aplicación

kapt { arguments { arg("room.schemaLocation", "$projectDir/schemas".toString()) } }

Cuando ejecuta o crea el proyecto, obtendrá un archivo JSON 2.json , que tiene todas las consultas dentro de la base de datos de su sala.

"formatVersion": 1, "database": { "version": 2, "identityHash": "325bd539353db508c5248423a1c88c03", "entities": [ { "tableName": "User", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", "columnName": "id", "affinity": "INTEGER", "notNull": true },

Por lo tanto, puede incluir el createSql anterior dentro de su método de migrate .

3. Obtenga una consulta de AppDatabase_Impl

Si no desea exportar el esquema, aún puede obtener la consulta ejecutando o AppDatabase_Impl.java el proyecto que generará el archivo AppDatabase_Impl.java . y dentro del archivo especificado que puede tener.

@Override public void createAllTables(SupportSQLiteDatabase _db) { _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");

Dentro del método createAllTables , habrá scripts de creación de todas las entidades. Puede obtenerlo e incluirlo dentro de su método de migrate .

4. Procesamiento de anotaciones.

Como puede suponer, Room genera todos los schema mencionados anteriormente y los archivos AppDatabase_Impl dentro del tiempo de compilación y con el procesamiento de anotaciones que agrega con

kapt "androidx.room:room-compiler:$room_version"

Eso significa que también puede hacer lo mismo y crear su propia biblioteca de procesamiento de anotaciones que genera todas las consultas de creación necesarias para usted.

La idea es hacer una biblioteca de procesamiento de anotaciones para las anotaciones de @Entity de @Entity y @Database . Tome una clase que está anotada con @Entity por ejemplo. Estos son los pasos que deberás seguir

  1. Cree un nuevo StringBuilder y agregue "CREAR TABLA SI NO EXISTE"
  2. Obtenga el nombre de la tabla de class.simplename o por el campo @Entity de @Entity . StringBuilder a su StringBuilder
  3. Luego, para cada campo de su clase, cree columnas de SQL. Tome el nombre, tipo, nulabilidad del campo por el campo en sí o por la anotación @ColumnInfo . Para cada campo, debe agregar el estilo id INTEGER NOT NULL de una columna a su StringBuilder .
  4. Agregar claves primarias por @PrimaryKey
  5. Agregue ForeignKey e Indices si existe.
  6. Después de terminar, conviértalo a cadena y guárdelo en una nueva clase que desee usar. Por ejemplo, guárdelo como a continuación

public final class UserSqlUtils { public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))"; }

Entonces, puedes usarlo como

val MIGRATION_1_2 = object : Migration(1, 2){ override fun migrate(database: SupportSQLiteDatabase) { database.execSQL(UserSqlUtils().createTable) } }

Hice una biblioteca para mí que puede consultar e incluso usar en su proyecto. Tenga en cuenta que la biblioteca que hice no está llena y solo cumple mis requisitos para la creación de tablas.

RoomExtension para una mejor migración

Aplicación que usa RoomExtension

Espero que haya sido útil.