如何在Swift结构体中让ObjectBox反向链接正常保存?
ObjectBox 关联关系同步异常问题
场景还原
定义的实体结构体
struct FFF: Entity, Identifiable { let id: Id let name: String // objectbox: backlink = "f" var ns: ToMany<NNN> } struct NNN: Entity, Identifiable { let id: Id let name: String var f: ToOne<FFF> }
关联操作代码
let path = NSTemporaryDirectory() + "/d" let store = try Store(directoryPath: path) let fffBox = store.box(for: FFF.self) let nnnBox = store.box(for: NNN.self) try fffBox.removeAll() try nnnBox.removeAll() let f0 = try fffBox.put(struct: FFF(id: 0, name: "X", ns: nil)) let n0 = try nnnBox.put(struct: NNN(id: 0, name: "Y", f: nil)) n0.f.target = f0 let n1 = try nnnBox.put(struct: n0) let f1 = try fffBox.put(struct: f0) print("f0 = \(f0)") print("n0 = \(n0)") print("f1 = \(f1)") print("n1 = \(n1)") let nstest = f1.ns print("nstest = \(nstest)")
实际输出
f0 = FFF(id: 1, name: "X", ns: ToMany<NNN>(unresolved)) n0 = NNN(id: 1, name: "Y", f: ToOne<FFF>(.stored(id: EntityId<FFF>(1), target: FFF(id: 1, name: "X", ns: ToMany<NNN>(unresolved))))) f1 = FFF(id: 1, name: "X", ns: ToMany<NNN>(unresolved)) n1 = NNN(id: 1, name: "Y", f: ToOne<FFF>(.stored(id: EntityId<FFF>(1), target: FFF(id: 1, name: "X", ns: ToMany<NNN>(unresolved))))) nstest = (unresolved)
问题
设置ToOne属性建立关联后,ToMany反向关联始终显示为空;反过来设置ToMany属性时,ToOne属性会变为nil,不清楚操作哪里出错,按照官方文档的结构体使用方式调用方法,认为流程是正确的。
问题分析与解决方案
核心错误点
- 值类型特性导致的同步失效:使用
struct作为实体(值类型),修改n0.f.target = f0后,原f0实例不会自动感知关联变化——值类型的修改是创建新实例,不会同步到已存储的对象中。 - 冗余的实体存储操作:修改
n0并存储为n1后,又存储了未做任何修改的f0为f1,这一步完全多余,且不会触发反向关联更新。 - 延迟加载的误解:
ToMany默认是延迟加载的,直接打印会显示unresolved,必须主动触发加载(比如访问count或遍历元素)才能获取实际关联数据。
修正后的代码
let path = NSTemporaryDirectory() + "/d" let store = try Store(directoryPath: path) let fffBox = store.box(for: FFF.self) let nnnBox = store.box(for: NNN.self) try fffBox.removeAll() try nnnBox.removeAll() // 创建并存储FFF实体 let f0 = try fffBox.put(struct: FFF(id: 0, name: "X", ns: nil)) // 创建NNN实体时直接关联FFF,再存储 var n0 = NNN(id: 0, name: "Y", f: ToOne(target: f0)) let n1 = try nnnBox.put(struct: n0) // 从数据库重新获取FFF实体,此时反向关联已被维护 let f1 = try fffBox.get(id: f0.id)! // 触发ToMany加载并查看结果 let nstest = f1.ns print("nstest 关联数量: \(nstest.count)") for n in nstest { print("关联的NNN实体: \(n)") }
关键说明
- 值类型的修改逻辑:由于
struct是值类型,修改关联后必须重新存储该实体,而不是修改旧实例后存储原关联对象。 - 反向关联加载方式:
ToMany属性需要通过访问元素或count触发数据库查询,加载完成后才能看到实际数据,直接打印只会显示未解析状态。 - 避免冗余操作:无需重复存储未修改的实体,ObjectBox会在存储
ToOne关联的实体时自动维护反向ToMany关系,但需要重新从数据库获取实体才能看到更新后的关联。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

