Realm Kotlin SDK多对多关系关联已存在Tag报错问题排查
问题排查:Realm多对多关联保存时重复主键异常
问题场景与代码
我尝试在Record与Tag对象间实现多对多关系,每个Record可关联多个Tag,对应的Kotlin实体类代码如下:
open class Record : RealmObject { @PrimaryKey var id: String = "" var title: String = "" var description: String = "" var tags: RealmList<Tag> = realmListOf() } open class Tag : RealmObject { @PrimaryKey var id: String = "" var name: String = "" val record: RealmResults<Record> by backlinks(Record::tags) }
测试保存Record对象时发现:保存关联不存在于Tags表的Tag时,该Tag会被自动添加;但保存关联已存在的Tag时,会抛出异常:
Attempting to create an object of type 'Tag' with an existing primary key value '1'
保存带Tag列表的Record对象的代码如下:
val record = Record().apply { id = randomUUID() title = "TestRecord" description = "Desc" tags = realmListOf( Tag().apply { id = "1" name = "Tag1" }, Tag().apply { id = "2" name = "Tag2" } ) } realm.write { copyToRealm(record) }
问题原因
你直接创建了未被Realm管理的新Tag对象并添加到Record的tags列表,调用copyToRealm()时,Realm会尝试将这些新Tag写入数据库。如果数据库中已存在同主键的Tag,就会触发重复主键异常——因为copyToRealm()仅支持写入未持久化的新对象,无法直接关联已存在的持久化对象。
解决方案
要正确关联已存在的Tag,需先从Realm中获取对应的持久化对象实例,再添加到Record的列表;对于不存在的Tag,则创建新对象写入。以下两种方式均可解决:
方式一:用copyToRealmOrUpdate()批量处理Tag
在写入Record前,先对每个Tag执行copyToRealmOrUpdate(),确保Tag要么被创建要么被更新,再关联到Record:
val record = Record().apply { id = randomUUID() title = "TestRecord" description = "Desc" } realm.write { // 处理每个Tag:存在则更新,不存在则创建,返回Realm管理的对象 val tag1 = copyToRealmOrUpdate(Tag().apply { id = "1" name = "Tag1" }) val tag2 = copyToRealmOrUpdate(Tag().apply { id = "2" name = "Tag2" }) // 将持久化后的Tag添加到Record列表 record.tags.addAll(listOf(tag1, tag2)) // 写入Record copyToRealm(record) }
方式二:先查询已存在的Tag,不存在再创建
先查询数据库中是否有对应主键的Tag,有则直接使用查询结果,没有则创建新对象:
val record = Record().apply { id = randomUUID() title = "TestRecord" description = "Desc" } realm.write { val tagIds = listOf("1", "2") val tags = tagIds.map { tagId -> // 查询已存在的Tag findLatest(Tag::class, tagId) ?: // 不存在则创建新Tag并写入 copyToRealm(Tag().apply { id = tagId name = "Tag$tagId" }) } record.tags.addAll(tags) copyToRealm(record) }
关键注意点
copyToRealm():仅能写入未被Realm管理的新对象,若对象主键已存在则抛出异常。copyToRealmOrUpdate():根据主键判断,存在则更新对象,不存在则创建,适合处理需要同步的关联对象。- 关联已存在的Realm对象时,必须使用Realm已管理的对象实例,不能用自己new出来的未持久化对象。
内容的提问来源于stack exchange,提问作者San
相关产品推荐
相关产品推荐

