Android Room一对一对象插入报错:外键约束失败排查
问题根源与解决方案
核心错误:外键关系完全搞反了
你在CategoryEntity里定义的外键把依赖关系写反了——逻辑上是Job属于Category,应该是JobEntity持有指向CategoryEntity的外键,而不是CategoryEntity依赖JobEntity。
最初的CategoryEntity里这段错误的外键配置,导致插入Category时,SQLite会检查是否存在对应的Job(因为你要求categoryId关联JobEntity的jobId),但此时Job还没插入,直接触发外键约束失败:
// 错误的外键配置,直接删掉! foreignKeys = [ ForeignKey( entity = JobEntity::class, parentColumns = ["jobId"], childColumns = ["categoryId"] ) ],
正确的实体定义
1. 修正CategoryEntity(去掉错误外键)
@Entity( tableName = "categories", indices = [Index("categoryName", unique = true)] ) data class CategoryEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "categoryId") val categoryId: Long = 0, @ColumnInfo(name = "categoryName") val name: String, @ColumnInfo(name = "categorySlug") val slug: String, )
2. 确认JobEntity的外键配置正确
你第二次修改的JobEntity方向是对的,可补充外键的行为(比如onDelete = CASCADE,删除Category时自动删除关联Job):
@Entity( tableName = "jobs", foreignKeys = [ ForeignKey( entity = CategoryEntity::class, parentColumns = ["categoryId"], childColumns = ["categoryId"], onDelete = ForeignKey.CASCADE // 可选,根据业务需求调整 ) ], indices = [Index("jobId", unique = true), Index("categoryId")] ) data class JobEntity( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "jobId") val jobId: Long = 0, @ColumnInfo(name = "categoryId") val categoryId: Long, @ColumnInfo(name = "title") val title: String, @ColumnInfo(name = "url") val url: String, @ColumnInfo(name = "description") val description: String, @ColumnInfo(name = "company_logo") val companyLogoUrl: String?, @ColumnInfo(name = "company_name") val companyName: String, @ColumnInfo(name = "job_type") val jobType: String?, @ColumnInfo(name = "publication_date") val publicationDate: String, @ColumnInfo(name = "candidate_required_location") val relocation: String, @ColumnInfo(name = "salary") val salary: String? )
调整插入流程(保持现有逻辑即可,关系已修正)
// 1. 创建CategoryEntity val categoryEntity = CategoryEntity( name = jobFromNetworkResponse.categoryName, slug = jobFromNetworkResponse.categoryName ) // 2. 插入Category并获取自增ID val categoryId = categoryLocalDataSource.insertCategory(categoryEntity) // 3. 用获取到的categoryId创建JobEntity val jobEntity = jobFromNetworkResponse.toEntity(categoryId) // 注意:修改toEntity方法,接收categoryId参数,而非整个CategoryEntity // 4. 插入Job localDataSource.insertJob(jobEntity)
额外注意点
- 确保
toEntity方法现在接收categoryId来构建JobEntity,不再嵌入整个CategoryEntity - 如果之前已创建错误的表结构,需升级数据库版本并编写迁移脚本,或卸载重装APP测试
内容的提问来源于stack exchange,提问作者noloman
相关产品推荐
相关产品推荐

