假设,我有一个简单的 Room 数据库:
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
现在,我要添加一个新实体:Pet 并将版本升级到 2:
@Database(entities = {User.class, Pet.class}, version = 2)
abstract class AppDatabase extends RoomDatabase {
public abstract Dao getDao();
}
当然Room会抛出异常:java.lang.IllegalStateException: A migration from 1 to 2 is necessary.
假设,我没有更改 User 类(所以所有数据都是安全的),我必须提供迁移,它只是创建一个新表。因此,我正在研究 Room 生成的类,搜索生成的查询以创建我的新表,将其复制并粘贴到迁移中:
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`))");
}
};
但是我发现手动操作很不方便。 有没有办法告诉 Room:我没有碰任何现有的表,所以数据是安全的。请为我创建迁移?
最佳答案
Room没有有一个好的迁移系统,至少在 2.1.0-alpha03 之前没有。
因此,在我们拥有更好的迁移系统之前,有一些解决方法可以在房间内轻松迁移。
由于没有 @Database(createNewTables = true) 或 MigrationSystem.createTable(User::class) 这样的方法,应该有一个,唯一可能的方法是运行
CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))
在您的 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`))")
}
}
为了获得上述SQL脚本,你有4种方法
基本上,您必须编写与 Room 生成的脚本匹配的上述脚本。这种方式可行,不可行。 (假设您有 50 个字段)
如果您在 @Database 注释中包含 exportSchema = true,Room 将在项目文件夹的/schemas 中生成数据库架构。用法是
@Database(entities = [User::class], version = 2, exportSchema = true)
abstract class AppDatabase : RoomDatabase {
//...
}
确保您在应用模块的 build.grade 中包含以下行
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}
当您运行或构建项目时,您将获得一个 JSON 文件 2.json,其中包含 Room 数据库中的所有查询。
"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
},
因此,您可以在 migrate 方法中包含上述 createSql。
如果您不想导出架构,您仍然可以通过运行或构建将生成 AppDatabase_Impl.java 文件的项目来获取查询。并在您可以拥有的指定文件中。
@Override
public void createAllTables(SupportSQLiteDatabase _db) {
_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id` INTEGER, PRIMARY KEY(`id`))");
在createAllTables 方法中,会有所有实体的创建脚本。您可以获取它并将其包含在您的 migrate 方法中。
您可能已经猜到,Room 会在编译时间内生成上述所有 schema 和 AppDatabase_Impl 文件,并使用您添加的注释处理
kapt "androidx.room:room-compiler:$room_version"
这意味着您也可以这样做并制作自己的注释处理库,为您生成所有必要的创建查询。
想法是为@Entity和@Database的Room注解做一个注解处理库。以使用 @Entity 注释的类为例。这些是您必须遵循的步骤
StringBuilder 并附加“CREATE TABLE IF NOT EXISTS”class.simplename 或 @Entity 的 tableName 字段获取表名。将其添加到您的 StringBuilder@ColumnInfo 注释获取字段的名称、类型、可空性。
对于每个字段,您必须将列的 id INTEGER NOT NULL 样式添加到您的 StringBuilder。@PrimaryKeyForeignKey 和 Indices(如果存在)。public final class UserSqlUtils {
public String createTable = "CREATE TABLE IF NOT EXISTS User (id INTEGER, PRIMARY KEY(id))";
}
然后,你可以把它当作
val MIGRATION_1_2 = object : Migration(1, 2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(UserSqlUtils().createTable)
}
}
我为自己制作了这样一个库,您可以查看它,甚至可以在您的项目中使用它。请注意,我创建的库并不完整,它只是满足我创建表的要求。
RoomExtension for better Migration
Application that uses RoomExtension
希望有用。
在撰写此答案时,房间版本为 2.1.0-alpha03,当我通过电子邮件发送给开发人员时,我收到了回复
It is expected to have better Migration System in
2.2.0
不幸的是,我们仍然缺乏更好的迁移系统。
关于java - 仅添加新表时的房间数据库迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48399852/
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
当谈到运行时自省(introspection)和动态代码生成时,我认为ruby没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资