SwiftData inverse relationship not updating

Given the code below the students array on the school is not being updated. Why?

Since the relationship is explicit and non-optional I would expect this to work.

import XCTest
import SwiftData

@Model
class School {
    var name: String
    @Relationship(deleteRule: .cascade, inverse: \Student.school)
    var students: [Student]

    init(name: String, students: [Student]) {
        self.name = name
        self.students = students
    }
}

@Model
class Student {
    var name: String
    var school: School

    init(name: String, school: School) {
        self.name = name
        self.school = school
    }
}

final class Test: XCTestCase {
    func testScenario() throws {
        let modelContainer = try ModelContainer(for:
            School.self,
            Student.self
        )
        
        let context = ModelContext(modelContainer)
        context.autosaveEnabled = false
        
        let school = School(name: "school", students: [])
        context.insert(school)
        
        let student1 = Student(name: "1", school: school)
        let student2 = Student(name: "2", school: school)
        context.insert(student1)
        context.insert(student2)
        
        XCTAssertEqual(school.students.count, 2) // XCTAssertEqual failed: ("0") is not equal to ("2")
    }
}
Answered by DTS Engineer in 804024022

This seems to be similar to the following post, and so you might take a look if haven't yet:

Basically, when you set up an object graph, insert the objects to the context before relate them. In you case, you might try the following:

@Model
class Student {
    var name: String
    var school: School?

    init(name: String, school: School) {
        self.name = name
        // Do not set up the relationship here.
        //self.school = school
    }
}

final class Test: XCTestCase {
        ...
        let school = School(name: "school", students: [])
        context.insert(school)
        
        let student1 = Student(name: "1", school: school)
        let student2 = Student(name: "2", school: school)
        context.insert(student1)
        context.insert(student2)
        
        // Relate the objects after inserting them to the context.
        student1.school = school
        student2.school = school
        try? context.save()

        XCTAssertEqual(school.students.count, 2) // XCTAssertEqual failed: ("0") is not equal to ("2")
    }
}

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Accepted Answer

This seems to be similar to the following post, and so you might take a look if haven't yet:

Basically, when you set up an object graph, insert the objects to the context before relate them. In you case, you might try the following:

@Model
class Student {
    var name: String
    var school: School?

    init(name: String, school: School) {
        self.name = name
        // Do not set up the relationship here.
        //self.school = school
    }
}

final class Test: XCTestCase {
        ...
        let school = School(name: "school", students: [])
        context.insert(school)
        
        let student1 = Student(name: "1", school: school)
        let student2 = Student(name: "2", school: school)
        context.insert(student1)
        context.insert(student2)
        
        // Relate the objects after inserting them to the context.
        student1.school = school
        student2.school = school
        try? context.save()

        XCTAssertEqual(school.students.count, 2) // XCTAssertEqual failed: ("0") is not equal to ("2")
    }
}

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

But are you saying that non-optional relationships do not work as intended in SwiftData?

You can manage to use non-optional relationship by setting the relationship to a default value in the initializer, and then re-set it later after the real target object is inserted to the context.

As I mentioned in the other post, I believe this is an area that SwiftData can be more intuitive, and would suggest that you file a feedback report for the SwiftData folks to take a look.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

SwiftData inverse relationship not updating
 
 
Q