房间没有更新数据库的架构
Posted
技术标签:
【中文标题】房间没有更新数据库的架构【英文标题】:Room is not updating schema of the database 【发布时间】:2022-01-23 20:02:55 【问题描述】:我有下表:
@JsonClass(generateAdapter = true)
@Entity(tableName = "lexeme")
data class Lexeme(
@PrimaryKey
@ColumnInfo(typeAffinity = ColumnInfo.INTEGER)
val id: Long,
val form: String,
val formNoAccent: String,
val formUtf8General: String,
val reverse: String,
val number: Int?,
val description: String?,
val noAccent: String?,
val consistentAccent: String?,
val frequency: String?,
val hyphenations: String?,
val pronunciations: String?,
val stopWord: String?,
val compound: String?,
val modelType: String?,
val modelNumber: String?,
val restriction: String?,
val staleParadigm: String?,
val notes: String?,
val hasApheresis: String?,
val hasApocope: String?,
val createDate: String?,
val modDate: String?
)
无论我想做什么,id
、form
、formNoAccent
和 formUtf8General
都没有设置为 Not Null
和 id
没有设置为 affinity = 3
,我都尝试过 Int和长。
我正在尝试将数据库预加载到我的应用程序中,但出现以下错误:
Expected:
TableInfoname='lexeme', columns=hyphenations=Columnname='hyphenations', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', staleParadigm=Columnname='staleParadigm', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modDate=Columnname='modDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', notes=Columnname='notes', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', hasApheresis=Columnname='hasApheresis', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', description=Columnname='description', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', consistentAccent=Columnname='consistentAccent', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', formNoAccent=Columnname='formNoAccent', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null', noAccent=Columnname='noAccent', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modelType=Columnname='modelType', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', reverse=Columnname='reverse', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null', compound=Columnname='compound', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', hasApocope=Columnname='hasApocope', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', frequency=Columnname='frequency', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', number=Columnname='number', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null', formUtf8General=Columnname='formUtf8General', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null', form=Columnname='form', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null', restriction=Columnname='restriction', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modelNumber=Columnname='modelNumber', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', id=Columnname='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null', stopWord=Columnname='stopWord', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', pronunciations=Columnname='pronunciations', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', createDate=Columnname='createDate', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', foreignKeys=[], indices=[]
Found:
TableInfoname='lexeme', columns=hyphenations=Columnname='hyphenations', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', staleParadigm=Columnname='staleParadigm', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modDate=Columnname='modDate', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', notes=Columnname='notes', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', hasApheresis=Columnname='hasApheresis', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', description=Columnname='description', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', consistentAccent=Columnname='consistentAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', formNoAccent=Columnname='formNoAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', noAccent=Columnname='noAccent', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modelType=Columnname='modelType', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', reverse=Columnname='reverse', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', compound=Columnname='compound', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', hasApocope=Columnname='hasApocope', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', frequency=Columnname='frequency', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', number=Columnname='number', type='integer', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null', formUtf8General=Columnname='formUtf8General', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', form=Columnname='form', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', restriction=Columnname='restriction', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', modelNumber=Columnname='modelNumber', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', id=Columnname='id', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', stopWord=Columnname='stopWord', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', pronunciations=Columnname='pronunciations', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', createDate=Columnname='createDate', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', foreignKeys=[], indices=[]
【问题讨论】:
【参考方案1】:确保 found 匹配 expected 的最简单方法是使用 Room 生成的 SQL 在工具中创建表用于创建预打包的数据库。
创建所有实体后编译项目,并将它们添加到使用@Database注解的类的实体列表中,可以找到该SQL。
编译后查看java(生成的),找到与@Database注解的类同名,后缀为_Impl。在该类中会有一个名为 createAllTables 的方法,它包含所有表、视图、索引的 SQL,以及房间期望的触发器的 FTS 表。
例如:-修复
您必须确保预打包数据库中的表(找到)与 SQL 中的表(预期)匹配。
假设您已经发现了所有差异,那么您可以尝试将 Lexeme 类更改为:-
@JsonClass(generateAdapter = true)
@Entity(tableName = "lexeme")
data class Lexeme(
@PrimaryKey
//@ColumnInfo(typeAffinity = ColumnInfo.INTEGER) //<<<<< effectively removed
val id: String, //<<<<< changed to be TEXT
val form: String?, //<<<<< changes to be NOT NULL
val formNoAccent: String?, //<<<<< changes to be NOT NULL
val formUtf8General: String?, //<<<<< changes to be NOT NULL
val reverse: String, //<<<<< changes to be NOT NULL (not found by yourself)
val number: Int?,
val description: String?,
val noAccent: String?,
val consistentAccent: String?,
val frequency: String?,
val hyphenations: String?,
val pronunciations: String?,
val stopWord: String?,
val compound: String?,
val modelType: String?,
val modelNumber: String?,
val restriction: String?,
val staleParadigm: String?,
val notes: String?,
val hasApheresis: String?,
val hasApocope: String?,
val createDate: String?,
val modDate: String?
)
请注意,我没有尝试上述方法(在某种程度上有但仍不能保证我发现了所有的不匹配)
您可能需要在其他代码中进行其他更改以适应,请特别注意 id 列,因为不会像预期的那样生成 id。
我个人不建议尝试将实体(预期)与现有表(找到)匹配。 所以我建议考虑以下因素来调整预打包的数据库以适应实体:-
以上修改后生成的SQL是:-
CREATE TABLE IF NOT EXISTS `lexeme` (
`id` TEXT NOT NULL,
`form` TEXT,
`formNoAccent` TEXT,
`formUtf8General` TEXT,
`reverse` TEXT NOT NULL, /* <<<<< ANOTHER MISMATCH SPOTTED */
`number` INTEGER,
`description` TEXT,
`noAccent` TEXT,
`consistentAccent` TEXT,
`frequency` TEXT,
`hyphenations` TEXT,
`pronunciations` TEXT,
`stopWord` TEXT,
`compound` TEXT,
`modelType` TEXT,
`modelNumber` TEXT,
`restriction` TEXT,
`staleParadigm` TEXT,
`notes` TEXT,
`hasApheresis` TEXT,
`hasApocope` TEXT,
`createDate` TEXT,
`modDate` TEXT,
PRIMARY KEY(`id`)
)
注意使用上述内容,因为 reverse 列是奇数列,检查找到的并发现它也不匹配(因此更改)。因此,为什么我建议不要尝试将 Entity 与预打包匹配,而是使用 Room 生成的 SQL 来创建/修改预打包。
如果您在预打包的数据库中有大量数据,那么您可以使用 SQL 来(如果您没有数据或数据很少,则只需删除词素表并按照第 2 步创建):-
重命名词位表,例如
ALTER TABLE lexeme RENAME TO lexeme_old;
使用从生成的 java 复制的词位表的 SQL 创建词位。
将数据从 lexeme_old 表复制到 lexeme 表,例如
INSERT INTO lexeme (SELECT * FROM lexeme_old);
使用 DROP TABLE IF EXISTS lexeme_old
删除 lexeme_old 表
可选择使用 SQL VACUUM;
关闭数据库,退出工具,启动工具,打开/连接数据库检查更改是否已应用,关闭数据库然后将预打包的数据库复制到应用程序。
请注意,由于 id 列是 TEXT,因此如果任何值不是有效的整数,那么您将收到 SQLITE_MISMATCH 错误。
请注意,以上假设没有其他实体/表或触发器会使事情复杂化(特别是如果 Lexeme 表是其他表的父级)。
注意,上述方法不一定有效(如果您查看下面链接的示例,它会删除索引、触发器和视图,并且在复制数据之前不会创建它们)
如果您确实获得了 SQLITE_MISMATCH,那么您可以执行以下操作之一:-
-
将 id 列从
val id: Long
更改为 val id: String
并删除行 @ColumnInfo(typeAffinity = ColumnInfo.INTEGER)
。
将步骤 3 中使用的 SQL 更改为
:-
INSERT INTO lexeme
(
`form`,
`formNoAccent`,
`formUtf8General`,
`reverse`,
`number`,
`description`,
`noAccent`,
`consistentAccent`,
`frequency`,
`hyphenations`,
`pronunciations`,
`stopWord`,
`compound`,
`modelType`,
`modelNumber`,
`restriction`,
`staleParadigm`,
`notes`,
`hasApheresis`,
`hasApocope`,
`createDate`,
`modDate`
)
SELECT
`form`,
`formNoAccent`,
`formUtf8General`,
`reverse`,
`number`,
`description`,
`noAccent`,
`consistentAccent`,
`frequency`,
`hyphenations`,
`pronunciations`,
`stopWord`,
`compound`,
`modelType`,
`modelNumber`,
`restriction`,
`staleParadigm`,
`notes`,
`hasApheresis`,
`hasApocope`,
`createDate`,
`modDate`
FROM lexeme_old
;
注意 SQL 没有被检查,认为它在原则上。
上述步骤可以在您使用/确实用于创建预打包数据库的任何工具中进行。
另一种选择是使用prePackagedDarabaseCallback
即时进行更改。 This is an example of using the callback 实际上只需进行一些更改即可完成上述步骤。但是,它是用 java 编写的,并且至少需要 Room 版本 2.4.0-beta02(建议使用 2.4.0,因为它现在已经发布)。
【讨论】:
以上是关于房间没有更新数据库的架构的主要内容,如果未能解决你的问题,请参考以下文章
我的RESTful API没有更新数据库,但是ajax返回成功