gemini0725 gemini0725 - 11 months ago 28
iOS Question

iOS entity inheritance with data in parent not retrieved in fetch of child

I have a parent entity in my model called P. I also have a child entity called C. I'm using the entity inheritance feature built into Core data as this solves problems for me (from what I read and understand).

Here is my situation:

In an early version of my development, I created a number of records in the P entity. Later I added the C entity and set the Parent entity to P. C only contains a single attribute. Due to the design of the app, it is better to have entity inheritance than to include the attribute in the parent entity.

Looking at articles on the web and in Apple's documentation, I understand that an sqlite persistent store will be a single table with all attributes which can cause performance problems, but I accept this (for now).

Looking at this, it would seem that fetching all entries from C would return all the entries in P. I have found that is not the case. A bit of testing shows this seems to be happening:

  • An object persisted to P does not show up in fetches of C but will in fetches of P.

  • An object persisted to C will show up in fetches of P and C.

  • Deleting the object added to C from P will remove it from both P and C.

This is my fetch code:

NSError *error;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"C"];
request.predicate = predicate;
request.includesSubentities = YES;
NSManagedObjectContext *moc = self.managedObjectContext;
NSArray *results = [moc executeFetchRequest:request error:&error];

predicate is nil so that I get all objects in the entity. There are no errors in the fetch request.

Here are my questions:

  1. Is there a query I should use for C that can return all the items originally only added to P?

  2. If not, is there a way to synchronize C to the existing items in P?

I have searched for entity inheritance on this and other sites and while there was a good deal of helpful information, nobody seemed to address this problem (although I could have missed something I am sure).

Ideally I would like to be able to add/edit/delete objects that are fetched from P but have the results show in C. Is this possible? From my early testing the delete works as desired, but add definitely does not. Edit is not yet tested.

Any and all help appreciated!

Answer Source

What you describe is what I would expect. Once you create an instance of entity P, it is not (and cannot become) an instance of entity C. So a fetch for entity C will never return those objects.

But, because entity C is a subentity of P, an instance of entity C is also an instance of entity P - albeit a "special" one with an extra attribute. So a fetch for entity P will (assuming you have set includesSubentities to YES) return both C entities and (plain) P entities. (By way of example, if P were "Animals" and C were "Dogs", a Dog is an Animal, and so a fetch for Animals should include Dogs. But a fetch for Dogs should not include any other types of Animal.)

If you fetch an object using a fetch for P entities, and delete it, then the object - whether it is actually an instance of C or P - will be deleted and removed from the store. So it will no longer appear in a fetch for C entities or P entities.

So to answer your specific questions:

  1. No, there is no way for a fetch for entity C to include objects created and stored as instances of entity P.
  2. The only way to "convert" instances of P into instances of C would be to create new instances of C and copy the relevant attribute values (presumably including a default value for the extra attribute) and then delete the original instances of P.