Search code examples
iossqlcore-datansfetchrequestnscompoundpredicate

Compound predicate not returning the results


I'm stuck with this problem for a while now I can't seem to think of a way to get it right. I'll try to explain it as clear as I can.

There are 3 entities in my core data model. Workplace, Patient and Handover.

enter image description here

A Workplace can have multiple Patients. Also a Patient can belong to multiple Workplaces.

A Patient can have one Handover and vice versa.

In the app, a list of Workplaces are shown to the user. When the user selects a Workplace, I need to get a set Patients who belong to that selected Workplace and have Handovers for today. Since a Patient can have multiple Handovers, there can be duplicate records for Patients and that's okay.

This is what I'm doing now. First I retrieve the Workplace object for the user selected. Then I iterate through it's Patients and extract the IDs of Patient objects and collect them in to an array. Then I pass the array of patient IDs and the date to filter out the Patients who have Handovers for the given date.

let workplace = db.loadWorkplace(155) // 155 is the ID of the Workplace

var patientIDs: [Int] = []
for p in workplace.patients {
    let patient = p as Patient
    patientIDs.append(patient.id)
}
handovers = db.loadHandovers(patientIDs, date: NSDate.date())

This is the method that des the filtering.

public func loadHandovers(patients: [Int], date: NSDate) -> [AnyObject] {

    let fetchRequest = NSFetchRequest()
    let entityDescription = NSEntityDescription.entityForName("Handover", inManagedObjectContext: managedObjectContext!)
    let patientPredicate = NSPredicate(format: "patient.id IN %@", patients)
    let datePredicate = NSPredicate(format: "date > %@ AND date < %@", getStartDate(date), getEndDate(date))

    let compoundPredicate = NSCompoundPredicate(type: .AndPredicateType, subpredicates: [patientPredicate, datePredicate])

    fetchRequest.entity = entityDescription
    fetchRequest.predicate = compoundPredicate

    var error: NSError?
    let result = managedObjectContext?.executeFetchRequest(fetchRequest, error: &error)
    return result!
}

The getStartDate() and getEndDate() methods convert the NSDate object and get its start time and end time to get a date frame. I have them used in some other places and they work. Here's a detailed explanation about it.

Anyway my loadHandovers() method returns 0 results. It cannot be because when I insert data, I can see Handovers for today. Below is the SQL query that is executed from core data.

SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZDATE, t0.ZSIGNEDBY, t0.ZSTATUS, t0.ZPATIENT 
FROM ZHANDOVER t0 
JOIN ZPATIENT t1 ON t0.ZPATIENT = t1.Z_PK 
WHERE ( t1.ZID IN  (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) 
AND ( t0.ZDATE > ? AND  t0.ZDATE < ?)) 

Can anyone please tell me if its something wrong with my predicates? Or if there are different ways to approach this altogether? I'd really appreciate it.

Thank you.


Solution

  • Using the object graph, this seems really simple. Try to avoid the verbose fetch requests.

    workplace.patients.filteredSetUsingPredicate(
      NSPredicate(format: "handovers.date > %@ && handovers.date < %@", 
                  startOfDay, endOfDay))
    

    You seem a bit confused about your own setup. If a patient only has one Handover, why call the relationship handovers in the plural?

    Another flaw with your setup is illustrated by the contradictory statement

    "Since a Patient can have multiple Handovers..."

    In your data model, a patient can have one handover, not many. The only explanation is that you are maintaining multiple Patient instances for the same patient, just because the patient has more than one handover. That is certainly illogical and a partial reason for your confusion and the error you encounter.

    A better data structure, avoiding duplicate patients:

    Workplace <<---->> Patient <---->> Handover

    This assumes that the handovers have nothing to do with the hospital. If they do, you should use the Handover entity as a kind of join table as suggested by @DanK:

    Workplace <---->> Handover <<----> Patient

    If this is what you want, the application of the predicate would be even shorter:

    workplace.handovers.filteredSetUsingPredicate(
      NSPredicate(format: "date > %@ && date < %@", startOfDay, endOfDay))