考虑到需要一个.db文件来预填充Room数据库,并在运行时说Pre-packaged database has an invalid schema
的问题。在许多列中只有两个不匹配,它们在Kotlin中都定义为Boolean
类型。
科特琳实体类:
@ColumnInfo(name = "xxx")
var xxx: Boolean = false ,
@ColumnInfo(name = "yyy")
var yyy: Boolean? = null
错误消息:
Expected:
TableInfo{name='zzz', columns={xxx=Column{name='xxx', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, yyy=Column{name='yyy', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='zzz', columns={xxx=Column{name='xxx', type='NUMERIC', affinity='1', notNull=true, primaryKeyPosition=0, defaultValue='null'}, yyy=Column{name='yyy', type='NUMERIC', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='null'}, foreignKeys=[], indices=[]}
正在使用用于创建预打包的.db文件DB Browser for SQLite
,这是用于创建实际zzz表的查询:
CREATE TABLE "zzz" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
...
"xxx" INTEGER NOT NULL DEFAULT 0,
"yyy" INTEGER DEFAULT NULL
);
即使xxx和yyy列被定义为INTEGER类型,但最终还是NUMERIC类型。
答案 0 :(得分:1)
打开并读取并检查的预打包数据库具有一个架构,其中xxx和yyy的列类型不是INTEGER而是NUMERIC(或视为NUMERIC)。
Room不能处理NUMERIC的类型,因为它基本上是包罗万象的类型,因此它无法确切地确定应用于成员变量的类型,它只能猜测。因此,该消息说,它认为预打包的数据库不适合其化身。
您需要使用将xxx和zzz列设置为INTEGER的模式来重新创建预打包的数据库,例如使用:-
CREATE TABLE "zzz" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
...
"xxx" INTEGER NOT NULL DEFAULT 0,
"yyy" INTEGER DEFAULT NULL
);
或者您需要更改预打包数据库中的zzz表,以使架构如上。简而言之,Room无法处理已定义的具有NUMERIC派生类型的列,因为它不知道如何处理诸如NUMERIC这样的类型,因为这种类型是一个包罗万象的东西。
要更改表,您可以在:-
中使用以下内容:DROP TABLE IF EXISTS zzz_amended;
CREATE TABLE IF NOT EXISTS "zzz_amended" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
/* ... */
"xxx" INTEGER NOT NULL DEFAULT 0,
"yyy" INTEGER DEFAULT NULL
);
INSERT INTO zzz_amended SELECT * FROM zzz;
DROP TABLE IF EXISTS zzz_old;
ALTER TABLE zzz RENAME TO zzz_old;
ALTER TABLE zzz_amended RENAME TO zzz;
DROP TABLE IF EXISTS zzz_old;
一个更简单的替代方法是使用 RoomDatabaseBuilder 的 createFromAsset 或 createFromFile 方法,但这可能需要更改其实体适合方法确定架构的方式。
用于表zzz的模式如下所示,其中xxx和yyy 属于INTEGER类型。并且正在使用createFromAsset()方法。但 由于某种原因,createFromAsset()的结果是xxx和yyy是 创建时定义的NUMERIC类型而不是INTEGER类型 zzz表。
请考虑以下数据库,其中包含您说已创建的表。例如
根据:-
该数据库位于so59224033.db
还要考虑以下简单应用程序:-
Zzz
@Entity(tableName = "zzz")
data class Zzz (
@PrimaryKey(autoGenerate = true)
var id: Long? = null,
@ColumnInfo(name = "xxx")
var xxx: Boolean = false ,
@ColumnInfo(name = "yyy")
var yyy: Boolean? = null
)
ZzzDao
@Dao
interface ZzzDao {
@Query("SELECT * FROM zzz")
fun getAllFromzzz() :List<Zzz>
}
AppDatabase
@Database(version = 1,entities = [Zzz::class])
abstract class AppDatabase :RoomDatabase() {
abstract fun getZzzDao() :ZzzDao
}
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appDatabase :AppDatabase = Room.databaseBuilder(this,AppDatabase::class.java,"mydb")
.allowMainThreadQueries()
.createFromAsset("so59224033.db")
.build()
val listofZzz = appDatabase.getZzzDao().getAllFromzzz()
for (z in listofZzz) {
Log.d("ZzzINFO","ID = " + z.id + " xxx = " + z.xxx + " yyy = " + z.yyy)
}
}
}
结果不存在任何冲突(因此,至少在使用最新的Room库以及可用代码的情况下,消除Room的错误):-
kapt 'androidx.room:room-compiler:2.2.2'
implementation 'androidx.room:room-runtime:2.2.2'
结果与预期的一样:-
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 1 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 2 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 3 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 4 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 5 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 6 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 7 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 8 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 9 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 10 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 11 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 12 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 13 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 14 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 15 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 16 xxx = false yyy = null
2019-12-08 08:55:23.196 19370-19370/? D/ZzzINFO: ID = 17 xxx = false yyy = null
2019-12-08 08:55:23.197 19370-19370/? D/ZzzINFO: ID = 18 xxx = false yyy = null
2019-12-08 08:55:23.197 19370-19370/? D/ZzzINFO: ID = 19 xxx = false yyy = null
2019-12-08 08:55:23.197 19370-19370/? D/ZzzINFO: ID = 20 xxx = false yyy = null
如果源数据库已更改,例如使用:-
那么结果是:-
Expected:
TableInfo{name='zzz', columns={yyy=Column{name='yyy', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, xxx=Column{name='xxx', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='zzz', columns={yyy=Column{name='yyy', type='NUMERIC', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='NULL'}, xxx=Column{name='xxx', type='typethatwillbe_N_U_M_E_R_I_C', affinity='1', notNull=true, primaryKeyPosition=0, defaultValue='0'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
即通过使用资产文件夹中与预期不符的数据库来复制您的问题。
即原因是资产文件夹中的数据库不正确。
我建议从资产文件夹中删除文件,再次检查列是否定义为INTEGER,然后将文件复制到资产文件夹中。