Realm Swift 代码,用于在 3 个具有关系的深表中查询/添加记录

Realm Swift code to query / add records in 3 deep tables with relationships

我在 Realm 中创建了三个表,它们之间存在确定的关系(LBContests <-> LBQuizzes <-> LBLeaders),每个都是多对多关系。这是为了表示 "LBContests" 中 "LBQuizzes" 的 "LBLeaders" 并且 LBLeaders 包含用户名的排行榜(为了简单起见,我保留了跟踪分数的其他字段详细信息作为示例) .

import Foundation
import RealmSwift

class LBContests: Object {
    @objc dynamic var contestName: String = ""
    let childrenLBQuizzes = List<LBQuizzes>()
}

class LBQuizzes: Object {
    @objc dynamic var quizName: String = ""
    let childrenLBLeaders = List<LBLeaders>()
    var parentContest = LinkingObjects(fromType: LBContests.self, property: "childrenLBQuizzes")
}

class LBLeaders: Object {
    @objc dynamic var userName: String = ""
    var parentQuizzes = LinkingObjects(fromType: LBQuizzes.self, property: "childrenLBLeaders")
}

知道了 contestName 和 quizName,我试图确定如何在与 LBQuizzes(具有已知的 quizName)相关的 LBLeaders 中添加用户名,并进一步与 LBContests(具有已知的 contestName)相关。

我尝试过搜索、阅读、观看视频——但它们都是针对简单的一两级关系,我需要处理三级关系。我只能将 LBQuizzes 附加到 LBContests.childrenLBQuizzes,但无法找到一种方法将 LBLeaders 记录附加到具有子 LBQuizzes 记录及其子 LBLeaders 记录的 LBContests 记录。 ..(对于已知的 contestName 和 quizName)

我知道我的部分问题是我不完全理解差异以及何时使用对象、结果和列表...我可以执行过滤器来获得结果,但我需要一个对象来要么引用子关系 and/or 以附加记录...

有人可以吗:

  1. 确定 Swift 领域代码以添加 LBLeader 记录(用户名) 对于已知的相关 LBQuizzes 和 LBContests

  2. 提供一个 概述如何、何时以及为何使用对象、结果和列表 正确

  3. 深入了解对象、结果和列表 可以一起使用或明确确定它们是否不能使用 一起(这是我的理解) - 你得到结果 and/or 列表 来自或被过滤的对象,但它们不是 可以从一个转换为另一个(即你不能使用 Result 或 像对象一样列出)

让我看看我能不能把它们连在一起。

1) 你有一个已知的比赛和一个已知的测验,你想在测验中添加一个新的 LB 领导者。有几种方法可以解决这个问题,但这里有一个很长的答案:

首先,我设置了两个竞赛,竞赛 0 有两个测验,竞赛 1 有一个测验。将其打印到控制台会导致

contest 0
  quiz 0
  quiz 1
contest 1
  quiz 2

然后,假设我想添加一个新的 LBLeader,John,来参加比赛 0,测验 1。这是代码。

let knownContest = "contest 0"
let knownQuiz = "quiz 1"
let leaderToAdd = LBLeaders()
leaderToAdd.userName = "John"

let contestResults = realm.objects(LBContests.self).filter("contestName == %@", knownContest)
if let thisContest = contestResults.first {
    let quizResults = thisContest.childrenLBQuizzes.filter("quizName == %@", knownQuiz)
    if let thisQuiz = quizResults.first {
        try! realm.write {
            thisQuiz.childrenLBLeaders.append(leaderToAdd)
        }
    }
}

当打印相同的信息时,John 被添加到比赛 0,测验 1。

contest 0
  quiz 0
  quiz 1
    John
contest 1
  quiz 2

还有其他方法可以完成同样的事情(例如较短的答案)。比如这一个liner returns 同问和杠杆的反比关系

let quizResults = realm.objects(LBQuizzes.self).filter("quizName == %@ AND ANY parentContest.contestName == %@", knownQuiz, knownContest)

2) 对象、结果和列表是三个不同的领域概念,在 Realm Documentation.

中会很好地介绍。

笼统地说:

Realm 对象是对象的单个实例,例如人或狗。 (考虑了很多因素 'Realm Objects' 但为简洁起见,我们将对其进行限制)

领域结果(对象)是从领域数据库返回的对象集。请记住,如我的第一个解决方案所示,首先返回 contestResults,但随后我可以在 quizResults 中获取这些对象的子集。此外,Realm 结果是实时更新的 - 它们会 'attached' 保存在数据库中,因此当对象进入或离开结果范围时,结果始终会反映出来。

列表是定义一对多关系的'container'。与数组非常相似,并且具有很多相同的功能。一个人有很多狗,所以这将很好地使用列表,您似乎正在这样做。一个问题是 LinkingObjects 的反向关系。注意它的 LinkingObjects(复数)所以如果你利用它,请记住这也意味着一只狗可以有很多人。优点是它会在写入数据时自动创建这些关系,但缺点是它不是单一的逆关系,因此您必须相应地进行编码(在我的示例中使用 .first)。

3) 巨大的问题,在 SO 的范围内无法真正回答,因为需要大量文档来解释所有这些交互。

一些深思:

Primary Keys 通常可以使事情变得更容易和更快,因为特定对象可以通过其唯一的主键来处理关系,而不是依赖于查询,在这种情况下,测验名字.

例如,如果您的对象都有一个主键,则将新的领导者添加到特定测验中就变成了

class LBQuizzes: Object {
    @objc dynamic var quiz_id = UUID().uuidString

然后您可以通过其 quiz_id 获取该特定对象并添加领导者。

let quizId = //whatever the primary key is of this quiz object
let quizObject = realm.object(ofType: LBQuizzes.self, forPrimaryKey: quizId)
try! realm.write {
    quizObject?.childrenLBLeaders.append(leaderToAdd)
}