【问题标题】:How do I completely recreate my database in Android Room?如何在 Android Room 中完全重新创建我的数据库?
【发布时间】:2017-06-28 18:48:30
【问题描述】:

我有一种情况,我希望能够使用 Android Room 对我的数据库进行硬重置。使用SQLiteOpenHelper,我可以通过编写一个方法来删除所有表和索引,然后手动调用SQLiteOpenHelper.onCreate()

我知道我可以通过房间访问SupportSQLiteOpenHelper 并自己放下所有桌子,但似乎没有一个开始娱乐过程的好​​方法。

另外,我知道我可以从每个表中删除每个项目而不删除它,但这不是我想要的。这不会重置自动递增的主键,因此新项目的“id”字段不会重置回 1。

谢谢!

编辑:
这是我希望能够在运行时任意做的事情。

编辑 2:
该方法应该是可维护的,即不涉及与 Room 的行为匹配的手写 SQL。理想情况下,会有某种方法检索 Room 生成的 SQL,或 SQLiteOpenHelper.onCreate() 等效方法。或任何其他解决此问题的方法! :)

【问题讨论】:

  • 这是一个功能请求,除了 Room 开发人员之外,不是现在任何人都可以解决的问题。我也需要这个功能!
  • 对于“另外,我知道我可以删除每个表中的每个项目而不删除它,但这不是我想要的。这不会重置自动递增的主键,所以新项目的“id”字段不会重置为 1。”你可以查看stackoverflow.com/a/45795870/3751576

标签: android android-room sqliteopenhelper


【解决方案1】:

我发现最简单的方法是通过 context.deleteDatabase(“name”) 执行此操作,然后在首次访问时通过 Room.databaseBuilder().addCallback 重新实例化并重新填充数据库。

【讨论】:

  • 那你如何删除数据库的静态实例呢?
【解决方案2】:

简单的答案是增加您的@Database 版本号。一般来说,您应该对架构更改执行此操作,但它会达到您清除数据库和重置所有主键值的目的。

@Database(entities = { Hello.class }}, version = 1) // <- you want to increase version by 1
@TypeConverters({})
public abstract class AppDatabase extends RoomDatabase {
    public abstract HelloDao helloTextDao();
}

编辑:如果您想在运行时执行此操作,我会清除您表中的所有数据(以避免出现 FK 问题),然后在您各自的所有表上调用 DROP TABLE table_name。然后您将需要编写查询来创建表,即:CREATE TABLE table_name (uid INTEGER PRIMARY KEY, name STRING);

不幸的是,这意味着您必须维护一个与您的 POJO 保持同步的创建表查询列表。理想情况下,您可以使用反射来生成查询,但是 @ColumnInfo 目前不支持反射,因为它的 RetentionPolicy 设置为 CLASS

希望这可以解决您的问题,请随时在 cmets 中要求进一步澄清。狩猎愉快!

【讨论】:

  • 是的,我相信这将完成应用程序更新之间的任务。但是,我希望能够在运行时任意执行此操作(我可以使用我描述的删除所有表并调用 onCreate() 的“旧”方法来执行此操作)。我已经更新了我的问题以反映这一点。
  • 嘿,我知道这是一种可能的解决方案。不幸的是,我不认为这是可以接受的。手动编写 SQL 以重新创建 Room 为您自动生成的内容是灾难的根源。微小的差异可能会产生可怕的错误。使用“旧”方法,我可以保证调用 onCreate() 将完全按原样重新创建表。我在这里不能保证。我想我希望我们能以某种方式访问​​ Room 的等效 onCreate() 方法,或其他一些硬重置方法?
  • 我想出的最佳解决方案是运行时解决方案(如您所愿)但是它会增加数据库上的版本号(而不是在您的实际代码中),这会在您的数据库时产生问题比如说版本 45,而您的代码显示版本 1。(如果适合您,您可以在每次出现此问题时更新版本号。所以它不是游戏破坏者,并且允许您重新创建数据库在运行时多次)。是否值得我为这个案例更新我的答案?
  • 我认为让数据库版本与代码版本不匹配不是一个好主意。我想避免谈论我的具体用例,但本质上我有一个充当搜索索引的数据库。我想在每次重新创建索引时重置数据库,这可能是很多次。在不重置主键的情况下清空表现在就足够了,但在开发过程中,分析具有一位数和两位数 ID 的数据库比分析多位数的数据库要好得多。所以,是的,我有一个特殊的(和抱怨的)用例,但在我切换到 Room 之前很容易:)
【解决方案3】:

这可能会对你有所帮助。

  1. 升级您的数据库版本

  2. 当您调用 DatabaseBuilder 时,请记住将其添加到您的代码中 fallbackToDestructiveMigration

    Room.databaseBuilder(context, Database::class.java, DB_NAME) .allowMainThreadQueries() .fallbackToDestructiveMigration() .build()

更多详情请参考this

【讨论】:

    【解决方案4】:

    就我而言,删除context.deleteDatabase(“name”) 的数据库仍然会缓存旧数据库的数据。

    我通过手动删除数据库文件解决了这个问题

    File databasesDir = new File(context.getApplicationInfo().dataDir + "/databases");
    new File(databasesDir, "MyDatabaseName.db").delete();
    

    【讨论】:

    • 非常简单的解决方案
    【解决方案5】:

    我无法找到以编程方式执行此操作的方法。

    但是,你可以去yourApp -> Long click -> App Info -> Storage & Cache -> clear both cache and Storage。

    清除存储会显示一个验证对话框,指示数据库将被销毁。

    【讨论】:

      【解决方案6】:

      根据hereherehere给出的答案,我可以这样做:

      public void deleteAndReset() {
          SQLiteDatabase database;
          database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath(MY_DATABASE_NAME), null);
          String deleteTable = "DELETE FROM " + MY_TABLE_NAME;
          database.execSQL(deleteTable);
          String deleteSqliteSequence = "DELETE FROM sqlite_sequence WHERE name = '" + MY_TABLE_NAME + "'";
          database.execSQL(deleteSqliteSequence);
      }
      

      【讨论】:

      • 级别太低,假定为单个表并假定为该表定义了一个 db 序列。
      • 这只是从表中删除数据,不会重新创建数据库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      相关资源
      最近更新 更多