swift里的Realm对象,如何实现多表联合查询(使用RealmSwift),以实现类似于mysql的 select a.* from a,b where a.id=b.id and b.name=? 呢?
一.A 和 B 没有关系
如果 A 和 B 之间没有直接的关系,可以通过手动查询和过滤来实现联合查询。
数据模型
import RealmSwift
class A: Object { @Persisted var id: Int @Persisted var name: String // 其他字段... }
class B: Object { @Persisted var id: Int @Persisted var name: String // 其他字段... }
|
查询实现
let realm = try! Realm()
// 目标 name let targetName = "someName"
// 1. 查询 B 中符合条件的 id let bResults = realm.objects(B.self).filter("name == %@", targetName)
// 2. 提取 B 中符合条件的 id 列表 let bIds = bResults.map { $0.id }
// 3. 查询 A 中 id 在 bIds 列表中的记录 let aResults = realm.objects(A.self).filter("id IN %@", bIds)
// 输出结果 for a in aResults { print("A: \(a)") }
|
二.A 和 B 是一对一关系
如果 A 和 B 是一对一关系,可以在 A 中定义一个 B 的引用,然后直接通过关系查询。
数据模型
import RealmSwift
class B: Object { @Persisted var id: Int @Persisted var name: String // 其他字段... }
class A: Object { @Persisted var id: Int @Persisted var name: String @Persisted var b: B? // 一对一关系 // 其他字段... }
|
查询实现
let realm = try! Realm()
// 目标 name let targetName = "someName"
// 直接查询 A 中 b.name 匹配的记录 let aResults = realm.objects(A.self).filter("b.name == %@", targetName)
// 输出结果 for a in aResults { print("A: \(a)") }
|
三.A 和 B 是一对多关系(A.List< B >)
如果 A 和 B 是一对多关系,可以在 A 中定义一个 List<B>,然后通过 ANY 关键字查询。
数据模型
import RealmSwift
class B: Object { @Persisted var id: Int @Persisted var name: String // 其他字段... }
class A: Object { @Persisted var id: Int @Persisted var name: String @Persisted var bs: List<B> // 一对多关系 // 其他字段... }
|
查询实现
let realm = try! Realm()
// 目标 name let targetName = "someName"
// 查询 A 中 bs 列表中任意一个 B 的 name 匹配的记录 let aResults = realm.objects(A.self).filter("ANY bs.name == %@", targetName)
// 输出结果 for a in aResults { print("A: \(a)") }
|
四.A 和 B 是一对多关系(B.owner=A)
如果 A 和 B 是一对多关系,但关系是通过 B 中的 owner 字段(即反向关系)来维护的,而不是在 A 中使用 List<B>,那么可以通过 LinkingObjects 来实现查询。
数据模型
在这种情况下,B 中会有一个指向 A 的 owner 字段,而 A 中不需要显式定义 List<B>。Realm 会自动通过 LinkingObjects 提供反向关系。
import RealmSwift
class A: Object { @Persisted var id: Int @Persisted var name: String // 不需要显式定义 List<B> }
class B: Object { @Persisted var id: Int @Persisted var name: String @Persisted var owner: A? // 指向 A 的引用 // 其他字段... }
|
查询实现
let realm = try! Realm()
// 目标 name let targetName = "someName"
// 1. 查询 B 中 name 匹配的记录 let bResults = realm.objects(B.self).filter("name == %@", targetName)
// 2. 提取 B 中符合条件的 owner(A 的引用) let aResults = bResults.compactMap { $0.owner }
// 输出结果 for a in aResults { print("A: \(a)") }
|
一对多优化:使用 LinkingObjects 实现反向查询
如果你希望在 A 中通过反向关系(LinkingObjects)直接访问关联的 B 对象,可以在 A 中定义 LinkingObjects。
修改数据模型
import RealmSwift
class A: Object { @Persisted var id: Int @Persisted var name: String // 定义反向关系 let bs = LinkingObjects(fromType: B.self, property: "owner") }
class B: Object { @Persisted var id: Int @Persisted var name: String @Persisted var owner: A? // 指向 A 的引用 // 其他字段... }
|
查询实现
通过 LinkingObjects,你可以直接查询 A 中关联的 B 对象。
let realm = try! Realm()
// 目标 name let targetName = "someName"
// 查询 A 中 bs 列表中任意一个 B 的 name 匹配的记录 let aResults = realm.objects(A.self).filter("ANY bs.name == %@", targetName)
// 输出结果 for a in aResults { print("A: \(a)") }
|