swift里的Realm对象,如何实现多表联合查询(使用RealmSwift),以实现类似于mysql的 select a.* from a,b where a.id=b.id and b.name=? 呢?

一.AB 没有关系

如果 AB 之间没有直接的关系,可以通过手动查询和过滤来实现联合查询。

数据模型

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)")
}

二.AB 是一对一关系

如果 AB 是一对一关系,可以在 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)")
}

三.AB 是一对多关系(A.List< B >)

如果 AB 是一对多关系,可以在 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)")
}

四.AB 是一对多关系(B.owner=A)

如果 AB 是一对多关系,但关系是通过 B 中的 owner 字段(即反向关系)来维护的,而不是在 A 中使用 List<B>,那么可以通过 LinkingObjects 来实现查询。

数据模型

在这种情况下,B 中会有一个指向 Aowner 字段,而 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)")
}