2

Similar or perhaps related to this question.

Say I have an object class "Zoo". It has a to-many relationship to objects of (abstract) type "Animal". As such, an Animal belongs to a Zoo object, and has the property 'zoo' and the Zoo object has the property 'animals'.

However, I am generally more interested in concrete sub-entities, such as Giraffe, or Monkey.

I would like to have a relationship property called "giraffes" and "monkeys", but also the property "animals". I would like to create Giraffe objects and add them to the Zoo.

How would this work? I can't specify in the relationships giraffes and monkeys that its inverse is "zoo" because this would be invalid (in the Core Data Editor).

I am generally working with the subclasses, but I need to always be able to ask them what Zoo they belong to, so need a common interface.

Would appreciate some help and please let me know if there's anything I could clarify.

Community
  • 1
  • 1
horseshoe7
  • 2,745
  • 2
  • 35
  • 49
  • What do you want to do with the `giraffes` / `monkeys` relationships? You imagine that they will offer you a convenience for something? – Wain Apr 02 '14 at 11:49
  • well, due to confidentiality reasons I can tell you they aren't giraffes or monkeys but something else. although they are 'mammals' they are basically totally different and i rarely care about them as animals but as their distinct class type. should also say I don't entirely understand what you're asking me. – horseshoe7 Apr 02 '14 at 11:53
  • Do you actually have multiple `Zoo` instances? As currently described you would need to add many relationships. But, using fetch requests is often better than using relationships anyway... – Wain Apr 02 '14 at 12:00
  • so have an animals/zoo relationship, then have a fetch request called `giraffes` and `monkeys`, right? How would I write that fetch request in the CoreData editor? I'm not much of an expert, but it would be important for me for this request to have cached results because I'm calling `.giraffes` and `.monkeys` WAY more often than `.animals` What about `addGiraffesObject:` (I use and love mogenerator) – horseshoe7 Apr 02 '14 at 12:15
  • `addGiraffesObject:` is a method to edit the relationship. Using a fetch request doesn't cache the results, but how often do you really need to iterate the full list of `giraffes` without any filtering / consideration of batch faulting? – Wain Apr 02 '14 at 13:03
  • quite often actually. because I only have say 50 giraffes... – horseshoe7 Apr 02 '14 at 14:42

3 Answers3

0

I think you choose a hard way to get what you want. Create your diagram like below and you can fetch everything you need. When you fetch a specific animal (let's say a monkey) you can always get their relations with other entities.

zoo -->> (to many) animal --> (to one) animalType

Boran
  • 949
  • 10
  • 17
  • i see, then when i do a fetch with the animal type, it will return a collection of concrete subclasses. Good idea. It just means what do I do about the following? `addGiraffesObject:` ?? Would I then implement this method in the subclass that just calls `addAnimalsObject:` ?? – horseshoe7 Apr 02 '14 at 14:40
  • and indeed I'd probably make animalType an enum on the abstract baseclass. – horseshoe7 Apr 02 '14 at 14:41
  • Yes, I think you got it right. Define animalType and add it to the animal object after that you can add set of animal objects or a single object to the zoo. – Boran Apr 03 '14 at 06:15
0

Based on your description, I'd consider removing the zoo <-> animal relationship as you don't use it often and it will be a burden to maintain. The relationship would also contain a potentially large number of items so you want finer grained control than the relationship alone allows. And, with other relationships you can specify the deletion semantics.

You like using specific methods so add explicit relationships between the Zoo and each of your animal sub-entities. Specify the deletion rules on each of these (so destroying the Zoo kills all the animals) if required. Each animal will have a link to the zoo and it will be appropriately named.

For the Zoo knowing all of the animals, use a fetch request. You don't use it often and, when you do, you should really be specifying the batch faulting approach.

Aside:

Generally you should use the relationship simply as the data source for a fetch request, specifically so that you can specify the batch faulting approach. Even if you have 50 giraffes, that's probably more than you will use at any one time for display on the UI. If you're doing a data operation then directly using the relationship could be good. But if you're listing the items on the UI you should use a fetch request where the predicate uses the relationship to filter the appropriate objects.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • I'll provide a little hint. A Zoo is a piece of Hardware, and Animals are Devices. Devices can differ greatly in their functionality, but they all have common properties, such as hardwareAddress, etc. So, being able to add an Animal to my Zoo, and being able to see my entire collection of Animals is of interest, though generally I'm interested in accessing the Device types directly as they have basically very little to do with one another.... Perhaps this better describes my requirements. – horseshoe7 Apr 02 '14 at 17:05
  • Sure, but it doesn't change anything as your zoo/animals explanation was fine. My answer is based around your described requirements / frequency of interaction / size of data / simplicity of code. – Wain Apr 02 '14 at 17:07
  • Yeah, I'll have a look into fetch requests then. If their results are cached, then it should prove to be pretty quick. It would seem to me that any Animal should know what Zoo it belongs to, and I can just put an Animal in a Zoo. I'm fairly new to such aspects of Core Data. – horseshoe7 Apr 02 '14 at 17:18
  • The results aren't cached (unless you cache them explicitly), if you do cache then you should turn each object into a fault so it isn't taking up memory when you aren't using it (certainly if running on iOS). Each animal would have a relationship to the zoo, just on the sub-entities, not the parent entity. – Wain Apr 02 '14 at 17:27
0

Thanks for all the suggestions. In the end, I have a zoo-animals relationship, and on the Zoo object I wrote a few helpers:

@property (nonatomic, readonly) NSArray *giraffes;  // or monkeys

- (NSArray*)giraffes
{
      NSArray *giraffes = [Giraffe MR_findByAttribute:@"zoo"
                                      withValue:self
                                     andOrderBy:@"name"
                                      ascending:YES
                                      inContext:self.managedObjectContext];

      return giraffes; 
}

The baseclass was more important than you think, and knowing the Core Data will cache quite a bit, if I call this fairly frequently the performance will not be a problem.

(I use MagicalRecord if that API call looks a little strange.)

horseshoe7
  • 2,745
  • 2
  • 35
  • 49