Reputation: 163
I have a problem migrating my Room database. In updated database I have to change one field from integer to double value. I read its not as easy as it sounds and in order to do that I have to create new temporary table with this changed property, copy all values from previous table, delete old one and finally rename the temporary table.
My entity has 2 indices, which are causing problems. Here is my current best solution that is not passing auto generated room migration validation.
oceny is the name of the original table, oceny_temp is the temportary name. Even though i am adding those indices in explicitly with create index the validation is still not passing as it says that in expected table has 2 indices and in found there is 0.
static final Migration MIGRATION_25_26 = new Migration(25,26) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS oceny_temp" +
"(`idOceny` TEXT NOT NULL, " +
"`idUcznia` TEXT, " +
"`idPrzedmiotu` TEXT, " +
"`semestr` INTEGER NOT NULL, " +
"`typOceny` INTEGER NOT NULL, " +
"`wartosc` TEXT, " +
"`wartoscDoSredniej` REAL, " +
"`czyProponowana` INTEGER NOT NULL, " +
"`kategoria` TEXT, " +
"`waga` REAL NOT NULL, " +
"`maxPunktow` REAL NOT NULL, " +
"`odczytana` INTEGER NOT NULL, " +
"`dataWystawienia` TEXT, " +
"`wystawiajacy` TEXT, " +
"`typOczekiwania` INTEGER NOT NULL, " +
"`wersjaRekordu` TEXT, " +
"`rekordUsuniety` INTEGER NOT NULL, " +
"PRIMARY KEY(`idOceny`), " +
"FOREIGN KEY(`idUcznia`) REFERENCES `uczniowie`(`idUcznia`) ON UPDATE NO ACTION ON DELETE CASCADE )");
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idPrzedmiotu ON oceny_temp (idPrzedmiotu)");
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idUcznia ON oceny_temp (idUcznia)");
// Copy the data
database.execSQL(
"INSERT INTO oceny_temp (idOceny, idUcznia, idPrzedmiotu, semestr, typOceny, wartosc, wartoscDoSredniej, czyProponowana, kategoria, waga, maxPunktow, odczytana, dataWystawienia, wystawiajacy, typOczekiwania, wersjaRekordu, rekordUsuniety) " +
"SELECT idOceny, idUcznia, idPrzedmiotu, semestr, typOceny, wartosc, wartoscDoSredniej, czyProponowana, kategoria, waga, maxPunktow, odczytana, dataWystawienia, wystawiajacy, typOczekiwania, wersjaRekordu, rekordUsuniety FROM oceny");
// Remove the old table
database.execSQL("DROP TABLE oceny");
// Change the table name to the correct one
database.execSQL("ALTER TABLE oceny_temp RENAME TO oceny");
}
};
The error message:
Migration didn't properly handle
oceny(de.wolterskluwer.idziennik.model.grades.Grade).
Expected:
TableInfo{name='oceny', columns={dataWystawienia=Column{name='dataWystawienia', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, typOczekiwania=Column{name='typOczekiwania', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, idPrzedmiotu=Column{name='idPrzedmiotu', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, kategoria=Column{name='kategoria', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, rekordUsuniety=Column{name='rekordUsuniety', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, wystawiajacy=Column{name='wystawiajacy', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, wersjaRekordu=Column{name='wersjaRekordu', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, maxPunktow=Column{name='maxPunktow', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}, czyProponowana=Column{name='czyProponowana', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, typOceny=Column{name='typOceny', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, semestr=Column{name='semestr', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, waga=Column{name='waga', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}, odczytana=Column{name='odczytana', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, idUcznia=Column{name='idUcznia', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, idOceny=Column{name='idOceny', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}, wartosc=Column{name='wartosc', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, wartoscDoSredniej=Column{name='wartoscDoSredniej', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0}}, foreignKeys=[ForeignKey{referenceTable='uczniowie', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[idUcznia], referenceColumnNames=[idUcznia]}], indices=[Index{name='index_oceny_idPrzedmiotu', unique=false, columns=[idPrzedmiotu]}, Index{name='index_oceny_idUcznia', unique=false, columns=[idUcznia]}]}
Found:
TableInfo{name='oceny', columns={dataWystawienia=Column{name='dataWystawienia', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, typOczekiwania=Column{name='typOczekiwania', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, idPrzedmiotu=Column{name='idPrzedmiotu', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, kategoria=Column{name='kategoria', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, rekordUsuniety=Column{name='rekordUsuniety', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, wystawiajacy=Column{name='wystawiajacy', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, wersjaRekordu=Column{name='wersjaRekordu', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, maxPunktow=Column{name='maxPunktow', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}, czyProponowana=Column{name='czyProponowana', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, typOceny=Column{name='typOceny', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, semestr=Column{name='semestr', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, waga=Column{name='waga', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}, odczytana=Column{name='odczytana', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, idUcznia=Column{name='idUcznia', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, idOceny=Column{name='idOceny', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}, wartosc=Column{name='wartosc', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, wartoscDoSredniej=Column{name='wartoscDoSredniej', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0}}, foreignKeys=[ForeignKey{referenceTable='uczniowie', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[idUcznia], referenceColumnNames=[idUcznia]}], indices=[]}
Additional info: i added IF NOT EXISTS to the create index, because it was crashing saying that the index already exists, which doesn't make sense to me
Upvotes: 6
Views: 2358
Reputation: 1399
The problem is that you're sending a "CREATE INDEX IF NOT EXISTS" command, but the index with the same name already exists, therefore no new index is created.
You can solve this by either dropping the existing index before trying to create the new one, or by simply moving the create index command at the end of the flow.
Here's the full code which should work:
static final Migration MIGRATION_25_26 = new Migration(25,26) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS oceny_temp" +
"(`idOceny` TEXT NOT NULL, " +
"`idUcznia` TEXT, " +
"`idPrzedmiotu` TEXT, " +
"`semestr` INTEGER NOT NULL, " +
"`typOceny` INTEGER NOT NULL, " +
"`wartosc` TEXT, " +
"`wartoscDoSredniej` REAL, " +
"`czyProponowana` INTEGER NOT NULL, " +
"`kategoria` TEXT, " +
"`waga` REAL NOT NULL, " +
"`maxPunktow` REAL NOT NULL, " +
"`odczytana` INTEGER NOT NULL, " +
"`dataWystawienia` TEXT, " +
"`wystawiajacy` TEXT, " +
"`typOczekiwania` INTEGER NOT NULL, " +
"`wersjaRekordu` TEXT, " +
"`rekordUsuniety` INTEGER NOT NULL, " +
"PRIMARY KEY(`idOceny`), " +
"FOREIGN KEY(`idUcznia`) REFERENCES `uczniowie`(`idUcznia`) ON UPDATE NO ACTION ON DELETE CASCADE )");
// Copy the data
database.execSQL(
"INSERT INTO oceny_temp (idOceny, idUcznia, idPrzedmiotu, semestr, typOceny, wartosc, wartoscDoSredniej, czyProponowana, kategoria, waga, maxPunktow, odczytana, dataWystawienia, wystawiajacy, typOczekiwania, wersjaRekordu, rekordUsuniety) " +
"SELECT idOceny, idUcznia, idPrzedmiotu, semestr, typOceny, wartosc, wartoscDoSredniej, czyProponowana, kategoria, waga, maxPunktow, odczytana, dataWystawienia, wystawiajacy, typOczekiwania, wersjaRekordu, rekordUsuniety FROM oceny");
// Remove the old table
database.execSQL("DROP TABLE oceny");
// Change the table name to the correct one
database.execSQL("ALTER TABLE oceny_temp RENAME TO oceny");
// Recreate the indices
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idPrzedmiotu ON oceny (idPrzedmiotu)");
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idUcznia ON oceny (idUcznia)");
}
};
Note that, since we already renamed the table at the end of the flow, we create the index upon that migrated table.
Upvotes: 3
Reputation: 566
It seems like some how the indices are lost when the table is renamed. So I resolved this issue by adding one more line after renaming my temporal table to the correct one. This creates the indices on the renamed table. For your case it would be like this ...
// Change the table name to the correct one
database.execSQL("ALTER TABLE oceny_temp RENAME TO oceny");
// Create the indices on the table
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idPrzedmiotu ON oceny (idPrzedmiotu)");
database.execSQL("CREATE INDEX IF NOT EXISTS index_oceny_idUcznia ON oceny (idUcznia)");
Upvotes: 5