简体   繁体   中英

Should my room database start at version 0?

I have realised that my database migration strategy was incorrect and have rewritten it. At the moment it looks like this:

@Database(entities = {SaveData.class, Achievement.class}, version = 2, exportSchema = false)
@TypeConverters(MapConverters.class)
public abstract class AppDatabase extends RoomDatabase {

    public abstract SaveDataDAO saveDataDAO();

    public abstract AchievementDAO achievementDAO();

}

With a helper class that looks like this:

public class AppDatabaseHelper {

    private static AppDatabase db;

    private AppDatabaseHelper() {
        // static utility
    }

    private static final Migration MIGRATION_1_2 =
            new Migration(1, 2) {
                @Override
                public void migrate(@NonNull SupportSQLiteDatabase database) {
                    Set<AchievementType> achievementTypes = EnumSet.allOf(AchievementType.class);
                    String values = achievementTypes.stream().map(AppDatabaseHelper::createRow).collect(Collectors.joining(", "));
                    String fullQuery = "INSERT OR IGNORE INTO Achievement(name, current, total) VALUES " + values;
                    database.execSQL(fullQuery);
                }
            };

    private static String createRow(AchievementType achievementType) {
        String name = achievementType.name();
        int total = achievementType.getTotal();
        return String.format("('%s',0,%s)", name, total);
    }

    public static AppDatabase getDatabase(Context context) {
        if (db == null) {
            db = Room.databaseBuilder(context.getApplicationContext(),
                    AppDatabase.class, "game")
                    .addMigrations(MIGRATION_1_2)
                    .build();
        }
        return db;
    }


}

When I delete the database and run the app, accessing the database for the first time does not run this migration as expected. Instead, I can see that the version of the database inside SQLLiteOpenHelper.java is 0, attempting to migrate to 2. Because of this specific part of the Android helper class:

                    db.beginTransaction();
                    try {
                        if (version == 0) {
                            onCreate(db);
                        } else {
                            if (version > mNewVersion) {
                                onDowngrade(db, version, mNewVersion);
                            } else {
                                onUpgrade(db, version, mNewVersion);
                            }
                        }
                        db.setVersion(mNewVersion);
                        db.setTransactionSuccessful();
                    } finally {
                        db.endTransaction();
                    }

inside the getDatabaseLocked method, I can see that it will not run any migrations if it starts at version 0, and will instead just set the version to be whatever you are migrating up to.

This behaviour doesn't make any sense to me, so I assume I am missing something. I have tried a hacky workaround of just forcing the migration to go to 1 (by creating a different RoomDatabase class) then running the above which works. I have also tried manually setting the database version to be 1, but this doesn't seem to be the right solution either.

Let me know if you need more code for context

I am not sure I've got right your trouble. Sorry if my answer below - it's not the case.

  • Room is a framework that uses a lots of annotations and during build process produces a lot of autogenerated code. Part of it - is the queries for SQLite that should be run when application starts and doesn't find any existing database. These queries are formed based on entities' structure, indices, foreign keys and so on.
  • Let's say you had database version 1 and during build was generated some code (code #1) with the queries like "CREATE TABLE IF NOT EXIST...".
  • After that you made some changes to tables' structure, changed version to 2. During build was generated another code (code #2) with the little bit different queries (including changes you've made to tables).
  • You've installed on device app with version 1, code #1 was invoked - tables were created (if you don't use prepopulation of database from assets - it was created empty). You begin to fill tables with data and then - updated to version 2. At that, code from your MIGRATION_1_2 block was invoked - in order to save your data and just to change tables' structure with "special" query.
  • But if you uninstalled your app from device and then installed app with version 2, your code #2 would be invoked to create tables actual for version 2, there is no need for migration, is it? So "0" version in this case - version of database installed before, since there was no database installed - it is 0.

It's not clear for me what kind of migration you expect (in Migration there is some block with insert some values). If the only change in this migration is -inserting some predefining values into some table - then maybe you should prepopulate your initial database from assets or from file ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM