Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data: inverse relationship for two relationships with same type

Tags:

core-data

In my app Core Data model I have Sheet and Text entities. Sheet entity can have two Text's: privacyNotes and termsOfUse.

Both of Text type. So in XCode data modeler I create to-one relationships called "privacyNotes" and "termsOfUse" in Sheet with Text destination. Next goes to-one relationship "sheet" in Text. Then I select that Text.sheet relationship as inverse for Sheet.privacyNotes. So far so good. But when I set same Text.sheet relationship as inverse for Sheet.termOfUse XCode deletes this relationship as inverse Sheet.privacyNotes!

I understand that relationships in DB can be not so simple compared to Objective-C objects relationships, but I really don't get why SQLite or (CoreData) can't reuse one relationship as inverse for FEW other relationships?

like image 942
HARDWARRIOR Avatar asked Feb 13 '11 15:02

HARDWARRIOR


People also ask

What is inverse relationship in Core Data?

Inverse relationships enable Core Data to propagate change in both directions when an instance of either the source or destination type changes. Every relationship must have an inverse. When creating relationships in the Graph editor, you add inverse relationships between entities in a single step.

What is a Core Data relationship?

Persistent storage has become an essential part of the majority of iOS apps nowadays. Core Data is a persistence and/or in-memory cache framework that consists of a very powerful set of other tools that can be used within the app.

What are fetched properties in Core Data?

Fetched Properties in Core Data are properties that return an array value from a predicate. A fetched property predicate is a Core Data query that evaluates to an array of results.

How do I use Core Data?

Use Core Data to save your application's permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device. To sync data across multiple devices in a single iCloud account, Core Data automatically mirrors your schema to a CloudKit container.


2 Answers

A little peek under the abstraction hood might be enlightening*: a relation can only be the inverse for exactly one other relation because, in the backing store, they're represented by the same data. If a Text and a Sheet can have a certain relationship, Core Data does what a good human data modeler would do and stores that relationship as succinctly as possible. The relation properties of the entity objects are just ways of looking at that relationship.

To get the effect of what you're going for: go ahead and give Sheet properties for privacyNote and termsOfUse; but give Text properties like sheetIAmTermsFor and sheetIAmPrivacyNoteFor, and set them as inverses appropriately. Then in the Text class, add a synthetic property along these lines:

// in interface
@property (nonatomic, readonly) Sheet *sheet;
// in impl
-(Sheet *)sheet
{
  if ([self sheetIAmTermsFor])
    return [self sheetIAmTermsFor];
  else
    return [self sheetIAmPrivacyNoteFor];
}

If you want to write a setter too, you'll have to decide which role that setter should bestow on the Text (which Core Data can't figure out for you, another reason a property can't be the inverse of two different properties.)

If you need to enforce a constraint that a Text can only ever be a "privacyNote" or a "terms" but never both, override the setters for sheetIAmTermsFor and sheetIAmPrivacyNoteFor, following Apple's pattern in the docs, and have each null the other property when set.

(* Apple regards the SQLite databases Core Data generates as private to their implementation, but inspecting their schemas can be very educational. Just don't be tempted to write shipping code that goes behind CD's back to poke at the db directly.)

like image 128
rgeorge Avatar answered Oct 06 '22 21:10

rgeorge


You are far better off having a one to many relationship between Sheet and Text with a validation limit of 2. Then you should have a type property in the text which declares it as either a privacyNotes or termsOfUse. From there you can add convenience methods to your Sheet subclass that allows you to retrieve either one.

like image 41
Marcus S. Zarra Avatar answered Oct 06 '22 21:10

Marcus S. Zarra