制作预打包的.db文件以预填充Room数据库

时间:2019-12-07 07:50:54

标签: android android-sqlite android-room

考虑到需要一个.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类型。

1 个答案:

答案 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表。

1。

请考虑以下数据库,其中包含您说已创建的表。例如

enter image description here

根据:-

enter image description here

该数据库位于so59224033.db

2

还要考虑以下简单应用程序:-

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)
        }
    }
}

3

结果不存在任何冲突(因此,至少在使用最新的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

4

如果源数据库已更改,例如使用:-

enter image description here

那么结果是:-

 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,然后将文件复制到资产文件夹中。