Код Realm Swift для запроса / добавления записей в 3 глубоких таблицах со связями - PullRequest
0 голосов
/ 26 января 2020

Я создал три таблицы в Realm, и между ними определены отношения (LBContests <-> LBQuizzes <-> LBLeaders), и каждая из них имеет отношение многие ко многим. Это должно представлять списки лидеров, где есть «LBLeaders» для «LBQuizzes» в «LBContests», а LBLeaders содержит userNames (я пощадил дополнительные детали поля, где счет отслеживается в качестве примера - для простоты).

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

Зная сведения оtestName и quizName, я пытаюсь определить, как добавлять userNames в LBLeaders, связанные с LBQuizzes (с известным quizName) и далее связанные с LBContests (с известным CompetName).

Я пробовал искать, читать, смотреть видео - но все они для простых одно- или двухуровневых отношений, и мне нужно обработать 3 уровня отношений. Я только смог добавить LBQuizzes в LBContests.childrenLBQuizzes, но не смог найти способ затем добавить запись LBLeaders в запись LBContests, которая имеет дочернюю запись LBQuizzes и ее записи childrenLBLeaders ... (для известных CompetName и quizName)

Я знаю, что часть моей проблемы заключается в том, что я не до конца понимаю различия и когда использовать объекты по сравнению с результатами по сравнению со списками ... Я могу выполнить фильтр, чтобы получить Результат, но мне нужен объект для ссылки на дочерние отношения и / или для добавления записи ...

Может кто-нибудь пожалуйста:

  1. Определить Царство Свифта код для добавления записей LBLeader (userName) для известных связанных LBQuizzes и LBContests

  2. Предоставить обзор того, как, когда и почему правильно использовать объекты, результаты и списки

  3. Предоставить информацию о том, как Объекты, Результаты и Списки могут использоваться вместе, или окончательно определить, если их нельзя использовать вместе. там (это мое понимание) - вы получаете результаты и / или списки от фильтруемых объектов или объектов, но они не могут быть преобразованы из одного в другое (т.е. вы не можете использовать результат или список как объект)

1 Ответ

0 голосов
/ 26 января 2020

Дайте мне посмотреть, смогу ли я ie все это вместе.

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

и при печати той же информации Джон добавляется в конкурс 0, викторина 1.

contest 0
  quiz 0
  quiz 1
    John
contest 1
  quiz 2

Существуют и другие способы выполнить sh то же самое (например, более короткий ответ). Например, этот вкладыш возвращает тот же тест и использует обратную связь

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

2) Объекты, результаты и списки - это три различных концепции Царства, которые довольно подробно описаны в Документация Царства .

Говоря в общем:

Объект Realm - это отдельный экземпляр объекта, например Person или Dog. (существует ряд вещей, которые считаются «объектами области», но мы будем ограничивать их для краткости)

Результаты области (объект) - это набор объектов, возвращаемых из базы данных области. Имея в виду, что, как показано в моем первом решении, сначала возвращаютсяtestResults, но затем я могу получить подмножество этих объектов в quizResults. Кроме того, результаты Realm обновляются в реальном времени - они остаются «привязанными» к базе данных, так как объекты входят или выходят из области результатов, результаты всегда отражают это.

Список - это «контейнер», который определяет отношения один ко многим. Очень похоже на массив и имеет много одинаковых функций. У человека много собак, так что это был бы хороший вариант использования Списка, который вы, похоже, делаете. Одна проблема - обратная связь LinkingObjects. Обратите внимание на его LinkingObjects (множественное число), поэтому, если вы используете это, имейте в виду, что это также означает, что собака может иметь много людей. Преимущество состоит в том, что он автоматически создает эти отношения при записи данных, но недостатком является то, что это не единичные обратные отношения, поэтому вы должны соответствующим образом кодировать (используя .first, как в моем примере).

3) ОГРОМНОЕ вопрос и на самом деле не несет ответственности в рамках SO, поскольку потребовалось бы МНОГО документации для объяснения всех этих взаимодействий.

Некоторая пища для размышлений:

Первичные ключи может, часто, сделать вещи намного проще и быстрее, работая со связями, так как указанные c объекты могут быть адресованы их уникальным первичным ключом вместо того, чтобы полагаться на запросы, в данном случае, имени теста.

Например, если все ваши объекты имеют первичный ключ, добавление нового лидера в заданную c викторину становится

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

, а затем вы можете получить этот указанный c объект через его 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)
}
...