swiftswiftuiswiftdata

SwiftData Query


Been learning SwiftData and ran into a hiccup. Let's say I have to data types User and Job

@Model
class User: Identifiable {
    var id = UUID().uuidString
    var name: String
    var jobs = [Job]()
    
    init(name: String) {
        self.name = name
        self.jobs = jobs
    }
}
@Model
class Job: Identifiable {
    var id = UUID().uuidString
    var name: String
    var user: User?
    
    init(name: String, user: User? = nil) {
        self.name = name
        self.user = user
    }
}

Now, I have a TabView with 2 tabs. One is PeopleView with a list of people and the other is the JobsView with a list of jobs. My idea is to add Users and then assign them a Job, from a list. Jobs would also be added

List of Users List of Jobs

Tapping on a name in a list of people, I get this menu, which lists all available jobs.

Jobs menu

When I choose one, it gets assigned to that person, which is expected. Now, since @Model are a class, selecting the same job for a different person, reassigns that job to the second person and it gets removed from the first person jobs array. This is due to @Model being a class and that is fine, but...

On the other hand, if I add a new instance of a job to a person, so they could all have a same job (task), the array of jobs in the second tab also gets an additional job with the same name. Seems like adding a job to a person.jobs array, also adds it to database in the array of Jobs.

Duplicated jobs

Does Querying jobs aggregates all possible jobs from all people in the database? How can I have only those jobs I added in the Jobs tab? @Query var jobs: [Job]

person.jobs.append(job)
try? ctx.save()
let copy = Job(name: job.name)
person.jobs.append(copy)
try? ctx.save()

Solution

  • The solution was to make sure there is a many-to-many relationship between the two.

    @Model
    class Job: Identifiable {
      var id = UUID().uuidString
      var name: String
      var users: [User] = [] <——- change
    
      init(name: String) {
        self.name = name
    }
    

    }