如何在Kotlin中为Room数据库预填充两张表?
问题原因
你连续调用createFromAsset的方式是错误的——Room的这个方法每次调用都会用指定的asset文件覆盖目标数据库,所以最终只有最后一个文件(animes.db)的内容会被保留,前一个文件的表数据会被完全覆盖,导致两张表无法同时预填充。
解决方案
有两种可行的解决方式,根据你的需求选择:
方案1:合并两个数据库文件(最简单)
把quotess.db和animes.db中的表合并到一个单独的数据库文件中:
- 使用SQLite可视化工具(比如DB Browser for SQLite、SQLiteStudio)打开其中一个数据库文件
- 打开另一个数据库,导出
Quotes或Anime表的结构和数据 - 将导出的表导入到第一个数据库中,保存为新的文件(比如
combined_quotes_anime.db) - 将合并后的文件放到
assets目录,修改代码只调用一次createFromAsset:
@Provides @Singleton fun provideDatabase( app: Application, )= Room.databaseBuilder(app, QuotesDatabase::class.java, "quotes_database") .createFromAsset("combined_quotes_anime.db") .fallbackToDestructiveMigration() .build()
方案2:使用Room回调手动导入第二张表数据
如果不想合并文件,可以利用Room的Callback,在数据库创建完成后,手动从第二个asset文件中读取数据并插入到对应表中:
第一步:实现数据库回调类
class AnimeDataImportCallback(private val context: Context) : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) // 从assets读取animes.db并复制到临时文件 context.assets.open("animes.db").use { inputStream -> val tempDbFile = context.getDatabasePath("temp_anime_db.db") FileOutputStream(tempDbFile).use { outputStream -> inputStream.copyTo(outputStream) } // 打开临时数据库读取Anime表数据 val tempDb = SQLiteDatabase.openDatabase(tempDbFile.path, null, SQLiteDatabase.OPEN_READONLY) tempDb.query("Anime", null, null, null, null, null, null).use { cursor -> // 批量插入到当前数据库的Anime表 db.beginTransaction() try { while (cursor.moveToNext()) { // 根据你的Anime实体类字段,从游标中获取对应值(示例字段请自行替换) val id = cursor.getLong(cursor.getColumnIndexOrThrow("id")) val animeName = cursor.getString(cursor.getColumnIndexOrThrow("name")) val quoteCount = cursor.getInt(cursor.getColumnIndexOrThrow("quote_count")) // 执行插入语句 db.execSQL( "INSERT INTO Anime (id, name, quote_count) VALUES (?, ?, ?)", arrayOf(id, animeName, quoteCount) ) } db.setTransactionSuccessful() } finally { db.endTransaction() } } // 清理临时文件和资源 tempDb.close() tempDbFile.delete() } } }
第二步:在数据库构建中添加回调
@Provides @Singleton fun provideDatabase( app: Application, )= Room.databaseBuilder(app, QuotesDatabase::class.java, "quotes_database") .createFromAsset("quotess.db") // 先加载第一个数据库的表 .addCallback(AnimeDataImportCallback(app)) // 导入第二个数据库的表数据 .fallbackToDestructiveMigration() .build()
注意事项
- 确保两个asset数据库中的表结构(列名、数据类型、约束)与Room实体类
Quotes、Anime完全一致,否则会出现插入失败或数据异常 fallbackToDestructiveMigration仅适合开发阶段,正式环境请编写合理的数据库迁移逻辑
内容的提问来源于stack exchange,提问作者Gokul Gadkar
相关产品推荐
相关产品推荐

