Search code examples
swiftpredicateswiftdata

SwiftData predicate when a relationship is optional


Consider the following relationship in SwiftData:

@Model
class Category: Decodable, Identifiable {
    var id: Int
    var title: String
    @Relationship var questions = [Question]() 
}

 @Model
 class Question: Decodable, Identifiable {
    var id: Int
    @Relationship var category: Category?
 }

The problem occurs when I try to fetch all questions from a category after saving them:

let catId = 7
let categoryPredicate = #Predicate<Category> { $0.id == catId }
let categoryDescriptor = FetchDescriptor(predicate: categoryPredicate)
let categories = try modelContext.fetch(categoryDescriptor)
if let cat = categories.first {
    cat.questions = parsedQuestions
}

//now try to fetch the questions out of the modelContext so they can be used and updated 
let questionPredicate = #Predicate<Question> { $0.category.id == catId } //THIS LINE THROWS THE ERRORS
let questionDescriptor = FetchDescriptor(predicate: questionPredicate)
            
do {
    questions = try modelContext.fetch(questionDescriptor)
} catch {
    fatalError("unable to find any questions for \(category.title)")
}

I get this set of errors:

Generic parameter 'ID' could not be inferred
Referencing instance method 'id' on 'Optional' requires that 'Category' conform to 'View'
Type '(ID) -> some View' cannot conform to 'BinaryInteger'

How can I compose a proper predicate without errors in this case?


Solution

  • Since your relationship is optional you need to use optional in your predicate

    let questionPredicate = #Predicate<Question> { $0.category?.id == catId }