You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftData一对多对多关系中ESet删除后数据残留问题求助

SwiftData一对多关系中删除子对象未清理数据库的解决方案

问题核心

你遇到的问题本质是EInfo与ESet之间的双向关系未正确配置,导致SwiftData的.cascade删除规则未生效:从eInfo.sets中移除ESet时,仅切断了关联关系,但数据库里的ESet实例仍被保留。

修复步骤

1. 修正模型的双向关联配置

SwiftData的级联删除依赖正确的双向@Relationship关联,需要为两个类的关系属性明确指定反向关联:

@Model
class EInfo {
    @Attribute(.unique) var id: UUID
    var exerciseID: String
    // 明确指定反向关联为ESet的exercise属性,保留.cascade删除规则
    @Relationship(deleteRule: .cascade, inverse: \ESet.exercise)
    var sets: [ESet]
    var index : Int
    // 同时明确与Workout的双向关联
    @Relationship(inverse: \Workout.exercises)
    var workout: Workout? = nil

    // 其余初始化和方法代码不变
}

@Model
class ESet {
    @Attribute(.unique) var id: UUID
    var index: Int
    var weight: Double
    // 明确指定反向关联为EInfo的sets属性
    @Relationship(inverse: \EInfo.sets)
    var exercise: EInfo? = nil
    var weight_ : Double{
        get {weight}
        set {weight = newValue}
    }
    var reps: Int
    var done: Bool = false

    // 其余初始化代码不变
}

配置后,SwiftData能识别到EInfo.sets和ESet.exercise是双向绑定关系,执行移除操作时会触发.cascade规则,自动删除数据库中的ESet实例。

2. 简化删除逻辑

你当前的删除代码冗余,可简化为直接处理排序后的集合,确保索引对应正确的ESet:

.onDelete(perform: { indexSet in
    let sortedSets = exerciseInfo.sets.sorted(by: { $0.index < $1.index })
    indexSet.forEach { index in
        guard index < sortedSets.count else { return }
        let targetSet = sortedSets[index]
        exerciseInfo.sets.removeAll(where: { $0.id == targetSet.id })
    }
})

3. 优化ESet添加逻辑

添加新ESet时,手动设置反向关联可避免关联延迟或失效:

.onTapGesture {
    let newSet = ESet(index: exerciseInfo.sets.count, done: false)
    newSet.exercise = exerciseInfo
    exerciseInfo.sets.append(newSet)
}

验证方法

修改完成后重新运行APP,执行删除操作后用DB Browser查看SQLite数据库:

  • 检查ESet表,被删除的实例应已移除
  • 检查SwiftData自动生成的关联表,对应关联记录也会被清理

内容的提问来源于stack exchange,提问作者rgarg02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:42:39