Android Room插入从表报外键约束错误code 787如何解决?
问题根因
你创建CheckListModel实例时,主键checkListModelID是默认值0L,此时你直接用这个0L初始化了所有关联的CheckListPoints的外键字段checkListColumnID。
当你调用insertCheckList插入主表数据时,因为checkListModelID设置了autoGenerate = true,Room会自动生成一个正整数作为新记录的主键,你内存里原有的CheckListModel实例的checkListModelID不会自动更新,依旧是0L。
插入子表时,子表携带的外键值是0,但主表中根本不存在checkListModelID = 0的记录,因此触发外键约束报错。
修复方案
步骤1:修改DAO插入主表的方法,返回自动生成的主键
Room的@Insert注解支持返回Long类型值,代表插入成功后该行的主键ID:
@Dao interface CheckListModelDBDao { // 修改返回值为Long,接收插入生成的主键 @Insert fun insertCheckList(data:CheckListModel): Long // 其余原有方法保持不变 @Insert fun insertCheckListPoint(vararg data:CheckListPoints) @Delete fun deleteCheckList(checkList: CheckListModel) @Transaction @Query("SELECT * FROM check_list_model " ) fun getEverything(): Flow<List<CheckListWithCheckListModel>> }
步骤2:修改插入逻辑,用真实主键更新子表外键
插入主表拿到生成的主键后,再更新所有子表的外键字段后再插入:
private suspend fun insert(checkList: CheckListModel, checkListPoints: List<CheckListPoints>){ // 插入主表,获取自动生成的真实主键ID val generatedModelId = database.insertCheckList(checkList) // 用真实主键生成新的子表实例,替换原有错误的外键值 val validPoints = checkListPoints.map { point -> point.copy(checkListColumnID = generatedModelId) } // 批量插入子表 database.insertCheckListPoint(*validPoints.toTypedArray()) }
可选优化:增加事务保证原子性
可以给插入逻辑加事务注解,避免主表插入成功、子表插入失败产生脏数据,直接在DAO中封装事务方法即可:
@Dao interface CheckListModelDBDao { // 原有方法保留 @Insert fun insertCheckList(data:CheckListModel): Long @Insert fun insertCheckListPoint(vararg data:CheckListPoints) // 新增封装的事务插入方法 @Transaction suspend fun insertCheckListWithPoints(checkList: CheckListModel, points: List<CheckListPoints>) { val id = insertCheckList(checkList) val validPoints = points.map { it.copy(checkListColumnID = id) } insertCheckListPoint(*validPoints.toTypedArray()) } // ...其余方法不变 }
内容的提问来源于stack exchange,提问作者GDTyka
相关产品推荐
相关产品推荐

