Search code examples
swiftcore-datansfetchedresultscontrollernsfetchrequest

Core Data: To-many predicate ignored


I have a Group <-->> Member relationship. In class Group: NSManagedObject { I have the following properties:

@NSManaged public var members: Set<Member>

 public var status: Int16 {
    set {
        self.willChangeValue(forKey: "status")
        self.setPrimitiveValue(newValue, forKey: "status")
        self.didChangeValue(forKey: "status")
        self.members.removeAll()
    }
    get {
        self.willAccessValue(forKey: "status")
        var status: Int16 = 0
        if let statusKey = self.primitiveValue(forKey: "status") as? Int16 {
            self.didAccessValue(forKey: "status")
            status = statusKey
        }
        return status
    }
}

In class Member: NSManagedObject I have the following properties:

@NSManaged public var memberOf: Group?
@NSManaged public var status: Int16

Requirement: filter based on: if Groups.status = 1 AND member.status = 1 (for each member)

I have the following code:

     let statusPredicate = NSPredicate(format: "status == %@", NSNumber(integerLiteral: 1))
     let statusMemberPredicate = NSPredicate(format: "ANY members.status == %d", 1)
     let compoundPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.and, subpredicates: [statusPredicate, statusMemberPredicate])
     print("compoundPredicate \(compoundPredicate)")

     let requestGroups: NSFetchRequest<Group> = NSFetchRequest()
     requestGroups.entity = Group.entity()
     requestGroups.predicate = compoundPredicate
     requestGroups.returnsObjectsAsFaults = false
     requestGroups.fetchBatchSize = 20
     frcGroup = NSFetchedResultsController(fetchRequest: requestGroups, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
     try? frcGroup?.performFetch()

     if let members = frcGroup?.fetchedObjects?.first?.members {
            for member in members{
                  print("member.status \(member.status)")
                }
             }
         }

I get the following Log:

compoundPredicate status == 1 AND ANY members.status == 1
member.status 0
member.status 1
member.status 0

I also tried the following and got the same log as above:

let statusMemberPredicate = NSPredicate(format: "members.status CONTAINS %d", 1)

It looks like it's fetching all of the members and ignoring the members.status == 1 predicate.

What am I doing wrong?


Solution

  • The predicate only determines whether the objects that are being fetched should be included in the results. It has no effect on the related objects. In your case, if a Group has status = 1, and any of its related Member objects has status = 1, then it will be included in the results. But its members property is unaffected by the predicate. It will include all the related members, even if they don't match the predicate. So your results are what I would expect.

    If you want to filter the members, you should do so separately after fetching the Group objects.