Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Core Data fetched properties to return the most recent entity?

I have two Entities that have a relationship like so...

Core Data

I want to create a fetched property on the conversation to return the most recent message that belongs to it. I don't want to have to maintain another relationship so having a fetched property seems like the way to go.

So what this boils down to is;

How can I limit the fetched property to one item?

and

How can I sort the items by timestamp?

like image 846
sobox studio Avatar asked Jun 12 '14 10:06

sobox studio


1 Answers

You can use a fetched property to solve that problem but there is a catch.

You can't define that fetched property in the model editor.

You can define that fetched property in code.

So yes, you can do it but the value is very low.

Update

Have you got an example of defining a fetched property in code? Where would I do this? The managedObjectModel?

Yes you would do this through the NSManagedObjectModel.

  1. You must do the edit before the model is added to a NSPersistentStoreCoordinator. As soon as a NSManagedObjectModel is added to a NSPersistentStoreCoordinator it becomes immutable.

  2. You grab the entity you care about and then then create a NSFetchedPropertyDescription.

  3. Add that NSFetchedPropertyDescription to the existing entity.

  4. Add the NSFetchRequest to the created NSFetchedPropertyDescription.

Once that is done you can then use the NSManagedObjectModel like normal. Pretty straight forward other than having to reach into the model which is unusual. The order that you do things is important. Take this example:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
ZAssert(mom, @"%@:%@ No model to generate a store from", [self class], NSStringFromSelector(_cmd));

//Inject a fetched property
NSEntityDescription *parentEntity = [mom entitiesByName][@"Parent"];

NSFetchedPropertyDescription *fetchedProperty = [[NSFetchedPropertyDescription alloc] init];
[fetchedProperty setName:@"lastTestEntity"];

NSMutableArray *properties = [[parentEntity properties] mutableCopy];
[properties addObject:fetchedProperty];
[parentEntity setProperties:properties];

NSFetchRequest *testEntityRequest = [[NSFetchRequest alloc] init];
[testEntityRequest setEntity:[mom entitiesByName][@"TestEntity"]];
[testEntityRequest setPredicate:[NSPredicate predicateWithFormat:@"parent == $FETCH_SOURCE"]];
[testEntityRequest setFetchLimit:1];

NSSortDescriptor *sortByDate = [NSSortDescriptor sortDescriptorWithKey:@"createDate" ascending:NO];
[testEntityRequest setSortDescriptors:@[sortByDate]];

[fetchedProperty setFetchRequest:testEntityRequest];

NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
ZAssert(coordinator, @"Failed to initialize coordinator");

Notice how I set the NSFetchRequest after the NSFetchedProperty has been added to the NSEntityDescription. If you do not set it afterwards you will get an error from Core Data. Radar has been filed but I suspect very few people have even looked at this stuff let alone filed a radar against the odd behavior.

like image 198
Marcus S. Zarra Avatar answered Oct 06 '22 23:10

Marcus S. Zarra