请在构建器中提供迁移,或者在构建器中调用fallbackToDestructiveMigration,在这种情况下,Room将重新创建所有表。

52

我正在使用带有RxJava2的Room。我在我的表格中添加了一列,因此我正在迁移到新版本。我已将我的数据库版本更改为2。

以下是我的迁移代码

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE users "
        +"ADD COLUMN address String");

    }
};

AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, DB_NAME)
.addMigrations(MIGRATION_1_2)
.build();
如果你想查看完整代码,我指的是Github上的这个示例,它没有迁移代码。

如果你想查看完整代码,我指的是Github上的这个示例,它没有迁移代码

https://github.com/alahammad/RoomSample

我按照文档中描述的步骤进行,但我的应用程序仍然崩溃。

错误日志

Process: demo.karaoke.sensibol.com.roomrajava2, PID: 13655
    io.reactivex.exceptions.OnErrorNotImplementedException: A migration from 1 to 2 is necessary. Please provide a Migration in the builder or call fallbackToDestructiveMigration in the builder in which case Room will re-create all of the tables.
        at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
        at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
        at io.reactivex.internal.operators.maybe.MaybeCallbackObserver.onError(MaybeCallbackObserver.java:83)
        at io.reactivex.internal.operators.maybe.MaybeObserveOn$ObserveOnMaybeObserver.run(MaybeObserveOn.java:99)
        at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
        at android.os.Handler.handleCallback(Handler.java:815)
        at android.os.Handler.dispatchMessage(Handler.java:104)
        at android.os.Looper.loop(Looper.java:194)
        at android.app.ActivityThread.main(ActivityThread.java:5643)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
     Caused by: java.lang.IllegalStateException: A migration from 1 to 2 is necessary. Please provide a Migration in the builder or call fallbackToDestructiveMigration in the builder in which case Room will re-create all of the tables.
        at android.arch.persistence.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:82)
        at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:118)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:256)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
        at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
        at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
        at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:193)
        at demo.karaoke.sensibol.com.roomrajava2.UserDao_Impl$4.call(UserDao_Impl.java:137)
        at demo.karaoke.sensibol.com.roomrajava2.UserDao_Impl$4.call(UserDao_Impl.java:135)
        at io.reactivex.internal.operators.maybe.MaybeFromCallable.subscribeActual(MaybeFromCallable.java:46)
        at io.reactivex.Maybe.subscribe(Maybe.java:3749)
        at io.reactivex.internal.operators.maybe.MaybeSubscribeOn$SubscribeTask.run(MaybeSubscribeOn.java:54)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:452)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)

你能添加错误日志吗? - Amjad Khan
@AmjadKhan,我已经添加了错误日志,请查看。 - BraveEvidence
你是否在你的AppDatabase类中添加了@Database(entities = {}, version = 1)注释?你的手机上是否安装了版本1,然后更新了代码并进行了迁移和版本=2的尝试安装? - lomza
@lomza 是的,我已经这样做了。对于版本1 @Database(entities = {User.class}, version = 1),我在手机上安装了应用程序,然后添加了一列并更改了@Database(entities = {User.class}, version = 2),然后再次在手机上安装了该应用程序。 - BraveEvidence
对于使用MigrationTestHelper测试迁移时遇到问题的任何人,请确保在runMigrationsAndValidate中传递迁移。 - Noah
显示剩余2条评论
5个回答

70
如果您不想提供迁移,并且特别希望在升级版本时清除数据库,请在数据库构建器中调用fallbackToDestructiveMigration
database = Room.databaseBuilder(context.getApplicationContext(),
                    UsersDatabase.class, "Sample.db")
            .fallbackToDestructiveMigration()
            .build();

升级数据库的版本号。
@Database(entities = [your_Entities::class], version = 2)
abstract class Your_RoomDataBase : RoomDatabase() {

我们需要更新数据库版本还是保持现状? - Kishan Solanki
迁移是在你的数据库发生更改时发生的,因此你需要升级你的数据库版本。这篇文章可以帮助你:https://medium.com/androiddevelopers/understanding-migrations-with-room-f01e04b07929 @KishanSolanki - Foroogh Varmazyar
fallbackTODestructiveMigration 每次新建或关闭并重新启动应用程序时,都会清除我的数据库。在迁移期间使用此临时方法。 - Harikrushna Patel
@KishanSolanki 是的,你需要更新版本号。 - Rehan Khan

38

在 build() 之前添加 ".fallbackToDestructiveMigration()"。


39
只有当您希望用户丢失所有保存的数据时,才这样做。 - jwitt98
@smitty1。同意。我也怀疑当程序员以后想要添加迁移时,他将会遇到来自旧版本的迁移问题。 - CoolMind

36

我从GitHub上运行了你的应用程序,并进行了从版本1到版本2的样例迁移。结果发现SQL查询中有一个错误。正确的应该是:

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE users "
        +"ADD COLUMN address TEXT");

    }
};

字符串 > 文本

最好将Room数据库实例设置为单例,并仅在Repo / CacheManager类中使用。请查看要进行的完整代码更改的gist - https://gist.github.com/lomza/0f311a1b1e9c896bc58dff925d65eab2


2
谢谢你的回答。让我检查一下,稍后再回复你。你抽出时间来检查我的代码对我非常重要,感激不尽。非常感谢。 - BraveEvidence
即使我写的是String而不是TEXT,它也能工作。问题出在我提供的单例类中,您可以在https://gist.github.com/lomza/0f311a1b1e9c896bc58dff925d65eab2中找到。 - BraveEvidence

15
如果可以接受丢失现有数据,创建数据库时调用fallbackToDestructiveMigration()构建器方法。 示例:
db = Room.databaseBuilder(getApplicationContext(),
                    User.class, "DB_Name")
            .fallbackToDestructiveMigration()
            .build();

5
在构建之前添加 ".fallbackToDestructiveMigration()",并且增加版本号,对我来说已经修复了问题。希望这也能为其他人解决问题。在此处查看。

需要改进 Room,以便通过适当的迁移工具来处理迁移,而不是将 Room 销售为可以自动处理更改的东西,而你仍然必须编写 SQL 查询。 - TheRealChx101

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接