4
votes

Background

I've got a core data database made of two stores (one repository for my data and one store for the user data), linked between them by fetched properties.

Let's say I have two entities such that the relationship between them is 0 to 1. Card 0 ----> 1 CardStatus

1) Card, containing reference data and some properties (externalKey, word, description, ...)

Fetch Properties - userData (pointing to CardStatus and using the externalKey to do the link between the 2 entities)

2) CardStatus, containing the status of each Card. This entity is stored in the user data store.

There are cases where I need to fetch cards based on their status (example: retrieve all the cards that are marked as expired, retrieved all the cards that are marked as new, etc...)

Question

What kind of predicate should I write to fetch Card entities based on values from the CardStatus entity?

I tried using my fetched property userData directly in the predicate, but it's not allowed by core data.

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath userData not found in entity '

Then I tried with a subquery (see below) - still doesn't work. Interestingly, it works fine when I do a filter directly on an NSArray (instead of a fetch request).

Example - Retrieving card with a specific status:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SUBQUERY(userData, $x, ($x.currentLevel == 0)).@count > 0)"];

Example - Retrieving card marked as new (i.e. no data in CardStatus):

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(SELF, $x, $x.userData.@count == 0).@count > 0"];

Any suggestion?

2

2 Answers

2
votes

I found the solution.

The query was correct and is now working fine. The problem was that I was using a child managedObjectContext in my thread, while those children contexts don't seem to accept the use of fetched properties.

I replaced this by (simply) creating a new managed object context directly based on my persistent store (in other words, this context and the context I'm using in the main thread are at the same level in the hierarchy).

Below is the code to illustrate what I'm describing:

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *child = [[NSManagedObjectContext alloc] init];
[child setPersistentStoreCoordinator:[appDelegate.managedObjectContext persistentStoreCoordinator]];

It's now working all fine.

0
votes

It seems to me that the CardStatus entity functions as some kind of enum to supplement the logic of your dynamic data store. I think this is not a good case for cross-store fetches. It seems a bit of overkill adding unnecessary complexity.

Rather, you could store the status in the Card entity directly as a normal attribute, maybe in a numeric format. You can use a cross-store fetch to get the name of the status from the static store if necessary.