Android Room数据库预填充问题:预设SQL查询未执行
解决Room数据库预填充问题
问题根源
- 文件类型错误:你把纯文本SQL脚本直接命名为
attributes.db,但createFromAsset要求传入的是已初始化完成的SQLite数据库文件,并非SQL语句文本。 - 表名不匹配:创建表的目标是
attributes,但插入语句指向attributes_in_detail,两者名称不一致。 - SQL语法错误:字符串值用了反引号
`,SQL中字符串常量必须用单引号'包裹。
正确实现方案
方案一:使用预创建的SQLite数据库文件(推荐)
- 创建并初始化SQLite数据库
- 用SQLiteStudio、DB Browser for SQLite等工具新建一个
attributes.db文件。 - 在工具中执行修正后的SQL:
CREATE TABLE IF NOT EXISTS `attributes` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `key` TEXT NOT NULL, `value` TEXT NOT NULL, `meta_data` TEXT DEFAULT '', `isActive` INTEGER NOT NULL ); INSERT INTO `attributes` (`key`, `value`, `isActive`) VALUES ('essentials', 'Rent/mortgage', 1); - 保存该.db文件,放入项目的
src/main/assets目录下。
- 用SQLiteStudio、DB Browser for SQLite等工具新建一个
- 匹配Room实体类
确保AppDataBase中的实体类与attributes表结构完全对应:
你的原有初始化代码无需修改,首次启动时Room会自动将assets中的.db文件复制到应用私有目录,后续数据库可正常读写编辑。@Entity(tableName = "attributes") data class Attribute( @PrimaryKey(autoGenerate = true) val id: Int = 0, val key: String, val value: String, val meta_data: String = "", val isActive: Int ) @Database(entities = [Attribute::class], version = 1) abstract class AppDataBase : RoomDatabase() { // 定义DAO接口 }
方案二:使用Room Callback执行初始化SQL
若不想提前创建.db文件,可通过Room的Callback在数据库首次创建时执行初始化逻辑:
- 定义Database Callback
val roomInitCallback = object : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) // 若已通过Room实体类创建表,可省略CREATE TABLE语句 db.execSQL(""" INSERT INTO `attributes` (`key`, `value`, `isActive`) VALUES ('essentials', 'Rent/mortgage', 1); """.trimIndent()) // 可添加更多预填充数据的INSERT语句 } } - 修改Room初始化代码
移除createFromAsset,添加回调:Room.databaseBuilder( context.applicationContext, AppDataBase::class.java, "wallet.db" ) .setQueryCallback(QueryInterceptor(), Executors.newSingleThreadScheduledExecutor()) .addCallback(roomInitCallback) .build()
额外注意事项
- 确保Room数据库版本号与操作匹配,后续修改表结构需添加Migration逻辑。
- 方案一中,assets内的.db文件结构必须与Room实体类完全一致,否则会触发初始化失败。
- 所有SQL语句中的字符串值必须用单引号包裹,避免语法错误。
内容的提问来源于stack exchange,提问作者Sv Harish
相关产品推荐
相关产品推荐

