Kotlin使用Room数据库报Foreign Key constraint failed错误排查
问题背景
已多角度排查相关代码、检索对应解决方案,了解到有说法称Room的自增主键字段不可作为外键关联的父列,但此前在Java语言中已成功实现同类逻辑,目前学习Kotlin开发时复现该逻辑却运行异常。
实体类定义
User实体
@Entity @Parcelize data class User( @PrimaryKey(autoGenerate = true) val id: Long, val email: String, val name: String, val defaultRecipient: String ) : Parcelable
University实体
@Parcelize @Entity( foreignKeys = [ForeignKey( entity = User::class, parentColumns = ["id"], childColumns = ["userId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE )], indices = [Index(value = ["userId"])] ) data class University( val userId: Long, @PrimaryKey @NonNull val name: String ) : Parcelable { override fun equals(other: Any?): Boolean { if(other !is University) return false return (this.name == other.name) && this.userId == other.userId } override fun toString(): String { return this.name } }
Semester实体
@Parcelize @Entity( foreignKeys = [ForeignKey( entity = University::class, parentColumns = ["name"], childColumns = ["universityName"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE )], indices = [Index(value = ["universityName"])] ) data class Semester( val title: String, val universityName: String, @PrimaryKey(autoGenerate = true) val id: Long ) : Parcelable
Course实体
@Parcelize @Entity( foreignKeys = [ForeignKey( entity = Semester::class, parentColumns = ["id"], childColumns = ["semesterId"], onDelete = ForeignKey.CASCADE, onUpdate = ForeignKey.CASCADE )], indices = [Index(value = ["semesterId"])] ) data class Course( val title: String, val code: String, val semesterId: Long, @PrimaryKey(autoGenerate = true) val id: Long ) : Parcelable
异常触发代码
执行以下数据插入逻辑时,系统抛出外键约束错误:
val user = userDao.getUser() userDao.insertUniversity(University(user.id, "Chuckles University")) val university = userDao.getUniversitiesByUser(user.id)[0] userDao.insertSemester(Semester("Fall 22", "Comsats Wah", 0)) val semester = userDao.getSemestersByUniversity(university.name)[0] userDao.insertCourse(Course("Introduction to Programming", "CSC100", semester.id, 0))
根因定位
- 「Room自增主键字段不可作为外键关联父列」的说法不成立,之前Java版本能正常运行就是直接证明,本次报错和自增主键特性无关。
- 核心错误是插入Semester时外键字段传值不匹配:刚插入的University记录名称为
Chuckles University,但构造Semester对象时传入的关联学校名称是"Comsats Wah",数据库中不存在对应name值的University记录,外键约束校验直接失败抛出异常,代码根本不会执行到后续查询学期、插入课程的步骤。 - 存在一处潜在隐患:当前构造Semester、Course等带自增主键的实体时,手动给id字段传0作为初始值,虽然Room默认会将自增主键传入的0识别为「需要自动生成ID」,但更稳妥的写法是给实体类的自增id字段设置默认值0,插入时不需要手动传入该参数,避免不必要的传值错误。
内容的提问来源于stack exchange,提问作者Asim
相关产品推荐
相关产品推荐

