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

标签 swift realm table-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")
}

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

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

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

有人可以吗:

  1. 识别 Swift Realm 代码以添加 LBLeader 记录(用户名) 对于已知相关的 LBQuizzes 和 LBContests

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

  3. 提供有关对象、结果和列表如何进行的见解 可以一起使用或明确确定它们是否不能使用 在一起(这是我的理解) - 你会得到结果和/或列表 from 或 对象被过滤,但它们不是 可从一种转换为另一种(即,您不能使用 Result 或 像对象一样列出)

最佳答案

让我看看是否可以将它们整合在一起。

1) 您有一个已知的竞赛和一个已知的测验,并且您想在测验中添加新的 LB Leader。有几种方法可以解决这个问题,但这里有一个很长的答案:

首先,我设置了两个竞赛,其中竞赛 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

还有其他方法可以完成同样的事情(例如较短的答案)。例如,这一行返回相同的测验并利用逆关系

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

2) 对象、结果和列表是三个不同的 Realm 概念,Realm Documentation 中将详细介绍它们。 .

笼统地说:

Realm 对象是对象的单个实例,例如人或狗。 (有很多东西被认为是“Realm 对象”,但为了简洁起见,我们将对其进行限制)

Realm 结果(对象)是从 Realm 数据库返回的对象集。请记住,如我的第一个解决方案所示,首先返回了 racingResults,但随后我可以在 quizResults 中获取这些对象的子集。此外,Realm 结果是实时更新的 - 它们保持“附加”到数据库,以便当对象进入或离开结果范围时,结果始终反射(reflect)这一点。

列表是一个定义一对多关系的“容器”。与数组非常相似,并且具有许多相同的功能。一个人有很多狗,所以这将是一个列表的好用途,您似乎正在这样做。一个问题是 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)
}

关于swift - Realm Swift 代码用于查询/添加具有关系的 3 个深表中的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59914836/

相关文章:

android - 使用 Realm + Okhttp 时无法获取崩溃的确切原因

mysql - 如何设计客户订单和账单的表格

mysql - 从两个链接的多对多关系中检索数据

ios - 如何防止变量被初始化两次?

ios - Tesseract CPU 使用率 100%

java - 如何更新 Realm Android 中的子对象

android - Realm 使用 RxJava 在事务中复制对象的正确方法

swift - 在 Spritekit 上的 SKTileMapNode 中设置物理主体

swift - 使用 Swift 将 NSAttributedString 转换为 NSString

Laravel 4 - 多对多 - 数据透视表不更新