【问题标题】:Adding elements on many-to-many relation在多对多关系上添加元素
【发布时间】:2019-09-26 23:45:00
【问题描述】:

我正在做一个项目,您可以(从学校的角度)计算每个学生的平均成绩。 您可以在一个屏幕上注册学生(第一个实体),在另一个屏幕上注册科目(第二个实体)。 学生有姓名、电子邮件、成绩和平均成绩作为属性,学科有姓名。它们相互之间是多对多的关系。

我正在尝试为每个学生创建一个科目列表的副本,然后我可以在每个学生上为每个科目注册一个成绩。像这样:

Model concept

型号: !https://imgur.com/gmXyR5j

我创建了一个单独的主题,因为它被用于多个位置:

import Foundation
import CoreData

class SubjectsManager {
    static let shared = SubjectsManager()
    var subjects: [Subject] = []

    func loadSubject(with context: NSManagedObjectContext) {
        let fetchRequest: NSFetchRequest<Subject> = Subject.fetchRequest()
        let sortDescritor = NSSortDescriptor(key: "name", ascending: true)
        fetchRequest.sortDescriptors = [sortDescritor]

        do {
            subjects = try context.fetch(fetchRequest)
        } catch {
            print(error.localizedDescription)
        }
    }

    func deleteSubject(index: Int, context: NSManagedObjectContext) {
        let subject = subjects[index]
        context.delete(subject)

        do {
            try context.save()
            subjects.remove(at: index)
        } catch {
            print(error.localizedDescription)
        }
    }

    private init() {

    }
}

而且,在我的学生屏幕上,我尝试了很多东西,但没有任何效果。 学生与学科的一对多关系称为registeredSubjects 我创建了一个名为 subjectsManagerSet 的 NSSET 来从单例中获取值,但它不起作用。这是我到目前为止所尝试的:

subjectManagerSet.addingObjects(from: subjectsManager.subjects)

还尝试创建 subjectManager.subjects 的 for 循环以添加 subjectManagerSet,但它也不起作用。

关于错误,当我从 xcode 输出中获取样本时,它一直显示 subjectManagerSet 没有从 subjectManager.subject 获取值

错误信息:

2019-09-26 20:38:16.983725-0300 MyAverage[1734:62290] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/vitorgomes/Desktop/Mentorizacao/MyAverage/MyAverage/Controllers/StudentsViewController.swift, line 119
(lldb) po subjectManagerSet
0 elements

预期的结果是我想要每个学生实例的科目副本,然后我可以为每个学生的每个科目添加成绩。

【问题讨论】:

  • virtu 你能截图或复制粘贴到你的问题中吗?StudentViewController.swift 文件第 119 行的代码(每个错误消息)?

标签: swift core-data nsset


【解决方案1】:

预期的结果是我想要每个学生的科目副本 例如,然后我可以为每个学生添加每个科目的成绩。

我不是按照您的问题开头所述解决您的问题,而是根据上面的引文在结尾处说明的问题。

我建议您重新考虑模型的结构。

也许是这样的?

在这个提议的模型中,您可以分配给实体Enrolment 的对象:

  • grade(和date)通过这些属性属性;
  • 学生通过一对多关系属性与Student 实体;
  • 主题通过一对多关系属性与Subject 实体。

在以下示例中,我假设 Core Data 生成了 NSManagedObject 子类 - 即 - 在 Data Model Inspector 中,设置 Codegen = Class Definition 的值(默认)。

(就个人而言,顺便说一句,我更喜欢为我的每个实体手动编写NSManagedObject 子类并使用Set 而不是NSSet,因为随后我发现在我的代码。但我在这里没有这样做,因为大多数刚接触 Core Data 的人都会使用上面提到的 Codegen 的默认值。)

您可以通过以下方式访问这些值...

    let student = Student()

    print("Student name is: \(String(describing: student.name))")

    if let studentEnrolments: NSSet = student.studentEnrolments {

        for item in studentEnrolments {

            if
                let enrolment = item as? Enrolment,
                let subjectName: String = enrolment.subject?.name {

                print("Subject name for this student is: \(subjectName)")
            }
        }
    }

为学生分配科目注册很容易...

    let enrolment = Enrolment()
    let subject = Subject()

    enrolment.subject = subject

    student.addToStudentEnrolments(enrolment)

那么现在或以后,可以将成绩应用到已注册的科目...

    let grade: String = "A"

    enrolment.grade = grade

当然,平均值变成了一个数学函数,基于每个学生所有成绩的总和除以计数。这是我的拙见,根据需要更好地构建,而不是保存为每个 Student 对象的属性。

更新

我正在更新我的答案以包含一些数据库理论来解释我提出的对象模型。

根据维基百科,Database normalisation 是...

构建关系数据库的过程 按照一系列所谓的范式,以 减少数据冗余并提高数据完整性。

这对我实际上意味着什么?这意味着将我的数据分解成最离散和最独特的部分,因此理论上我不需要多次输入任何独特的数据。

让我用一个简单的表格示例来解释这一点,因为它可能在电子表格(或您的模型概念)中列出:

原始数据

     TABLE 1
     A          B           C
1    STUDENT    SUBJECT     GRADE    
2    Student1   Mathematics 8.8
3    Student1   Physics     7.0
4    Student1   Biology     6.0
5    Student2   Mathematics 5.0
6    Student2   Physics     9.0
7    Student2   Biology     7.0

标准化数据

     TABLE 1                             TABLE 2              TABLE 3
     A          B           C            A     B              A     B
1    STUDENT    SUBJECT     GRADE        ID    STUDENT        ID    SUBJECT
2    1          1           8.8          1     Student1       1     Mathematics
3    1          2           7.0          2     Student2       2     Physics
4    1          3           6.0                               3     Biology
5    2          1           5.0
6    2          2           9.0
7    2          3           7.0

标准化数据使用三个表之间的关系。它存储每个STUDENT 和每个SUBJECTID(作为主键),而不是实际的单词。这在许多不同的方面显然要高效得多,包括但不限于:存储数据的字节数、索引能力、数据检索速度。

当您在 Core Data 对象模型图中设置 relationship 属性时,您正在做同样的事情......

因此,对于您的示例,Core Data 对象模型图 Entity 替换了 TABLE。 Core Data 框架在构造表时自动为我们插入一个主键列到 SQLite 数据库中,然后当我们以编程方式添加行(记录,也就是实体的实例)时,它会自动插入一个主键唯一整数。虽然我们作为开发人员(使用 Core Data)无法直接访问它,但 Core Data 框架允许我们建立一对一、一对多和多对多的关系 在两个实体之间实现相同的结果。

     Enrolment                           Student              Subject
     A          B           C            A     B              A     B
     Rel.       Rel.        Att.         Rel.  Att.           Rel.  Att.
     ∞          ∞                        1                    1
Z_PK Student    Subject     grade        Z_PK  name           Z_PK  name
1    1          1           8.8          1     Student1       1     Mathematics
2    1          2           7.0          2     Student2       2     Physics
3    1          3           6.0                               3     Biology
4    2          1           5.0
5    2          2           9.0
6    2          3           7.0

Att. = 实体属性

Rel. = 实体关系

= 多方面的一对多关系 (

1 = 一对多关系的一侧 (-->)


有任何问题,请告诉我?

【讨论】:

  • 所以,基本上,招生是学生和科目之间的连接表,对吧?我在 Apple 的文档上看到了一些内容,当您创建多对多关系时,它会自动为您创建一个连接表,但是,我不知道我是否错过了下一部分,但它没有解释更多关于这个自动连接表的信息。我在许多文件上寻找这个并没有找到它。我到家时会试试你的建议,现在我在工作中使用窗户。
  • 为了更好地解释这句话,我画了一张:imgur.com/ymema8J 这就是我计划应用程序的方式。每个学生都应该有一个科目的副本,然后这些学生可以为每个学生条目注册他们的成绩。
  • 很抱歉您必须使用 Windows
  • 它不是真正的连接表......正如您在评论中提到的,连接表是由 Core Data 框架在 SQLite 数据库中创建的,用于多对多关系。如果你使用终端打开你的 SQLite 数据库,你可以通过命令.schema 看到这些。我的建议是对您的模型进行理论上的调整......我会更新我的答案以更好地解释。
  • PS:我建议您编辑您的问题以添加/包含您的绘图。它清楚地解释了您想要实现的目标,并且在他人尝试提供自己的答案(可能比我的答案更好)或寻找解决自己问题的方法时会大有帮助。值得注意的是,有些用户不阅读 cmets。它还确保与您的问题相关的所有信息都集中在一个位置,使用户更容易理解整个上下文。
猜你喜欢
  • 2012-04-24
  • 2018-10-28
  • 2014-12-03
  • 1970-01-01
  • 2013-01-22
  • 2018-04-04
  • 1970-01-01
  • 2016-02-24
  • 2019-04-22
相关资源
最近更新 更多