SwiftData does not retrieve my inverse one-to-many Relationship

Here is my models:

import SwiftData

@Model
final public class FirstModel {
    let name: String

    @Relationship(deleteRule: .cascade, inverse: \SecondModel.parent) var children = [SecondModel]()

    init(name: String) {
        self.name = name
    }
}

@Model
final public class SecondModel {
    let parent: FirstModel
    let name: String

    @Relationship(deleteRule: .cascade, inverse: \ThirdModel.parent) var children = [ThirdModel]()

    init(name: String, parent: FirstModel) {
        self.name = name
        self.parent = parent
    }
}

@Model
final public class ThirdModel {
    let parent: SecondModel
    let name: String

    init(name: String, parent: SecondModel) {
        self.name = name
        self.parent = parent
    }
}

Then I create my model entries:

let schema = Schema([
    FirstModel.self,
    SecondModel.self,
    ThirdModel.self
])

let container = try ModelContainer(for: schema)
let context = ModelContext(container)

let firstModel = FirstModel(name: "my first model")
let secondModel = SecondModel(name: "my second model", parent: firstModel)
let thirdModel = ThirdModel(name: "my third model", parent: secondModel)

context.insert(firstModel)
context.insert(secondModel)
context.insert(thirdModel)

try context.save()

I want to retrieve the children from my models:

print("-- Fetch Third Model")
let thirdFetchDescriptor: FetchDescriptor<ThirdModel> = FetchDescriptor<ThirdModel>(predicate: #Predicate { $0.name == "my third model" })
let thirdModels = try context.fetch(thirdFetchDescriptor)
for entry in thirdModels {
    print(">>> \(entry) - \(entry.parent) - \(entry.parent.parent)")
}

print("-- Fetch First Model")
let firstFetchDescriptor: FetchDescriptor<FirstModel> = FetchDescriptor<FirstModel>(predicate: #Predicate { $0.name == "my first model" })
let firstModels = try context.fetch(firstFetchDescriptor)
for entry in firstModels {
    print(">>> \(entry) - \(entry.children)")
    for child in entry.children {
        print("\t>>> \(child) - \(child.children)")
    }
}

... But it does not seem to work:

-- Fetch Third Model
>>> cardapart_sdk_app_ui.ThirdModel - cardapart_sdk_app_ui.SecondModel - cardapart_sdk_app_ui.FirstModel

-- Fetch First Model
>>> cardapart_sdk_app_ui.FirstModel - []

What I would expect to see:

-- Fetch First Model
>>> cardapart_sdk_app_ui.FirstModel - [cardapart_sdk_app_ui.SecondModel]
    >>> cardapart_sdk_app_ui.SecondModel - [cardapart_sdk_app_ui.ThirdModel]

I am not sure what I am doing wrong or missing...

Answered by DTS Engineer in 788697022

Your code actually throws the following error when saving the context (if you add do...try... catch for context.save())

SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=1570 "%{PROPERTY}@ is a required value." UserInfo={NSValidationErrorObject=<NSManagedObject: 0x60000210bcf0> (entity: ThirdModel; id: 0x60000028c520 <x-coredata://D5C58BB3-E4F5-4A17-94E7-B9CA97968B02/ThirdModel/t1C6B0E7B-99CD-4877-9657-5A84D61AD5FB2>; data: {
    name = "my third model";
    parent = nil;
}), NSLocalizedDescription=%{PROPERTY}@ is a required value., NSValidationErrorKey=parent, NSValidationErrorValue=null}

To avoid the error, change the to-one relationship to Optional. Also, when declaring a relationship, use var because SwiftData maintains it for you.

If you declare your models in the following way, your code will work:

final public class SecondModel {
    var parent: FirstModel?
    ...
}

@Model
final public class ThirdModel {
    var parent: SecondModel?
    ...
}
Accepted Answer

Your code actually throws the following error when saving the context (if you add do...try... catch for context.save())

SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=1570 "%{PROPERTY}@ is a required value." UserInfo={NSValidationErrorObject=<NSManagedObject: 0x60000210bcf0> (entity: ThirdModel; id: 0x60000028c520 <x-coredata://D5C58BB3-E4F5-4A17-94E7-B9CA97968B02/ThirdModel/t1C6B0E7B-99CD-4877-9657-5A84D61AD5FB2>; data: {
    name = "my third model";
    parent = nil;
}), NSLocalizedDescription=%{PROPERTY}@ is a required value., NSValidationErrorKey=parent, NSValidationErrorValue=null}

To avoid the error, change the to-one relationship to Optional. Also, when declaring a relationship, use var because SwiftData maintains it for you.

If you declare your models in the following way, your code will work:

final public class SecondModel {
    var parent: FirstModel?
    ...
}

@Model
final public class ThirdModel {
    var parent: SecondModel?
    ...
}
SwiftData does not retrieve my inverse one-to-many Relationship
 
 
Q