Adding elements on many-to-many relation

给你一囗甜甜゛ 提交于 2021-02-04 21:34:40

问题


I am making a project where (from the perspective of school) you can calculate each student average. You can register a student (first entity) on a screen and subjects (second entity) on another screen. Student has name, email, grade and average as atributes, and Subjects has name. They relate many-to-many with each other.

I am trying to create a copy of subjects list to each student, then on each student i can register a grade to each subject. Like this:

Model concept

Model: !https://imgur.com/gmXyR5j

I've created a singleton of subjects since it is used more than one location:

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() {

    }
}

And, on my student screen, i've tried many thing but nothing is working. The to-many relation of student with subject is called registeredSubjects I've created a NSSET called subjectsManagerSet to get values from the singleton, but it not working. Here what i've tried so far:

subjectManagerSet.addingObjects(from: subjectsManager.subjects)

Also tried to create a for loop of subjectManager.subjects to add on subjectManagerSet but it's not working too.

About errors, when i get samples from xcode output, it keep showing that subjectManagerSet did not get values from subjectManager.subject

Error message:

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

The expected result is that i want a copy of subjects for each student instance, then i can add grades for each subjects for each student.


回答1:


The expected result is that i want a copy of subjects for each student instance, then i can add grades for each subjects for each student.

I am not addressing your problem as stated at the beginning of your question, but the one stated at the end, per the quote above.

I would encourage you to reconsider the structure of your model.

Perhaps something like this?

In this proposed model, you're able to assign to an object of the entity Enrolment:

  • a grade (and date) via these attribute properties;
  • a student via the one-to-many relationship property with a Student entity;
  • a subject via the one-to-many relationship property with a Subject entity.

In the following examples, I assume Core Data generated NSManagedObject subclasses - that is - in the Data Model Inspector, set the value for Codegen = Class Definition (default).

(Personally and as an aside, I prefer to manually write NSManagedObject subclasses for each of my entities and use Set rather than the NSSet, as I find it subsequently a lot easier to maintain type integrity in my code. But I have not done that here as most people who are new to Core Data will use the default for Codegen noted above.)

You're able to access these values in the following manner...

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

Its easy to assign a subject enrolment to a student...

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

    enrolment.subject = subject

    student.addToStudentEnrolments(enrolment)

Then now or later, a grade can be applied to the enrolled subject...

    let grade: String = "A"

    enrolment.grade = grade

Of course the average becomes a mathematical function based on the sum of all grades for each student, divided by the count. This is in my humble opinion, better constructed as it is needed, rather than saved as an attribute with each Student object.

Update

Im updating my answer to include a little database theory to explain my proposed object model.

According to Wikipedia, Database normalisation is...

the process of structuring a relational database in accordance with a series of so-called normal forms in order to reduce data redundancy and improve data integrity.

What does this practically mean to me? It means breaking my data down into its most discrete and unique parts, so that, in theory, I never need to enter any unique piece of data more than once.

Let me use a simple table example as a means of explaining this, as it might be set out in a spreadsheet (or your model concept):

Original Data

     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

Normalised Data

     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

The normalised data uses relationships between the three tables. It stores the ID (as a primary key) of each STUDENT and each SUBJECT, instead of the actual words. This is obviously far more efficient in many different ways, including but not limited to: bytes of stored data, ability to index, speed of data retrieval.

When you set a relationship property in your Core Data object model graph, you are doing the same thing...

So for your example, the Core Data object model graph Entity replaces TABLE. The Core Data framework automagically inserts a primary key column into the SQLite database for us when it constructs the tables and later a primary key unique integer when we programmatically add rows (records, a.k.a instances of an entity). While we don't have direct access to that as a developer (using Core Data), the Core Data framework allows us to build one-to-one, one-to-many and many-to-many relationships between two entities, that achieves the same outcome.

     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. = Entity Attribute;

Rel. = Entity Relationship;

= many side of one-to-many Relationship (<<-);

1 = one side of one-to-many Relationship (-->)


Any questions, let me know?



来源:https://stackoverflow.com/questions/58126027/adding-elements-on-many-to-many-relation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!