Core Data on iOS 5 Tutorial: How To Work with Relations and Predicates

This is a tutorial where you’ll learn how to work with predicates and relationships in Core Data. It is written by iOS Tutorial Team member Cesare Rocchi, a UX designer and developer specializing in web and mobile applications. Good news – by popular request, we now have a 4th part to our Core Data tutorial […] By Cesare Rocchi.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 6 of this article. Click here to view the first page.

Relationships, But Not the Dating Kind

In database terminology, a relationship is a “connection” between two entities. It’s often translated into everyday language using the verbs to have or to belong. Think of the classic example of employees and departments – an employee is said to belong to a department, and a department has employees.

In database modeling, relationships can be of three types: one-to-one, one-to-many and many-to-many. This property is usually referred to as cardinality. In the example from the previous section, there is already a relation modeled in Core Data: the one between FailedBankInfo and FailedBankDetails.

This is a one-to-one relationship: each info object can have exactly one details object associated with it and vice versa. The graphical view stresses this point by connecting the two entities with one single arrow line. In other words, these two only have eyes for each other. :]

Whenever you define a relationship, you have to specify the following:

In your example, a department can have more than one employee, so this is a to-many relation. As a general rule, a one-to-many relation has a many-to-one inverse. In case you want to define a many-to-many relationship, you simply define one relation as to-many and its inverse as a to-many as well.

Make sure you define an inverse for each relationship, since Core Data exploits this information to check the consistency of the object graph whenever a change is made.

  1. Name: This is just a string identifying the name of the relation.
  2. Destination entity: This is the target or the destination class of the relation. For example, the relationship that goes from an employee to the department can be called “department.” In this case, the employee is called the source and the department is the destination.
  3. Cardinality: The answer to the question: Is the destination a single object or not? If yes, the relation is of type to-one, otherwise it is a to-many. Assuming that in your scenario an employee can belong to just one department, the “department” relation is a to-one.
  4. Inverse relationship: The definition of the inverse function. It is pretty rare to find a domain where this is not needed. It is also a sort of logical necessity: if an employee belongs to a department, it means that that department has employees. An inverse relation just switches the “direction” of the original relation.
  5. Delete rule: This defines the behavior of the application when the source object of a relationship is deleted.

For the delete rule in #5 above, there are four possible values:

  • Nullify is the simplest option. For example, if you delete a department, the “department” value of each employee previously belonging to that department is set to null. Nobody is fired :]
  • No action means that, when you delete a department there is no change to the “department” value of each employee. They just keep thinking they have not been fired :]
  • Cascade may have side effects, so you should use it carefully. If you select cascade as the delete rule, then when you delete the source object it also deletes the destination object(s). So, if you’re shutting down a department but want to keep the employees, you should not use cascade. Such a rule is appropriate only if you want to close a department and fire all of its employees as well. In this case it is enough to set the delete rule for department to cascade and delete that department record.
  • Deny, on the other hand, prevents accidental deletions. If you’ve set deny as the delete rule, before you can delete a department you have to make sure all its employee instances have been deleted or associated with another department.

Delete rules have to be specified for both sides of a relationship, from employee to department and vice versa. Each domain implements its own business logic, so there is no general recipe for setting delete rules. Just remember to pay attention when using the cascade rule, since it could result in unexpected consequences.

For example, if both department -> employee (to-many) and employee -> department (to-one) are set to cascade, the deletion of a user triggers the deletion of a department which in turn fires back the deletion of all its employees! It is likely you don’t want that. In this particular case, the deletion rule for employee -> department should be set to nullify.

Note: Even though you access a relationship via dot syntax, as if it were a property, it isn’t: instead it corresponds to an actual query in the database. To maximize the performance of your application, remember this when you devise your data model and try to use relationships only if necessary.

Adding a Many-to-Many Relationship

Now you’re going to extend your data model by adding a new entity, connected to the info object with a many-to-many relationship.

In a real-world scenario, you probably wouldn’t model data this way. You’re doing it in this tutorial only to cover a complex situation with predicates (see below). The first step is to add a new entity.

Open FailedBankCD.xcdatamodeld and add a new entity named “Tag.” Then add a single attribute to it, “name” (1).

Then add a relationship, named “bankdetails,” whose destination is FailedBankDetails (2) and set its type to to-many (3). The delete rule is the default, nullify (4). This means that if a tag is deleted, the “linked” detail objects are not deleted but simply lose a tag.

To define its inverse, select FailedBankDetails (1), add a new relationship called “tags” with Tag as the destination, and set the inverse to bankdetails (2). As above, this is a to-many relationship (3) with a delete rule of nullify.

You should end up with the following graphical model, where FailedBankDetails acts as a sort of bridge between FailedBankInfo and Tag.

With all three entities selected, open the Editor menu item and choose “Create NSManagedObject Subclass…” Then select your project folder as the save destination. Select “Replace” when asked to overwrite the definition of the previous classes. A new class, named Tag, will pop up in your project tree.

Note: Sometimes, (quite often, in fact :p) Xcode will mess up the code generation and add a second instance of existing Core Data entities to the project tree. If this happens to you, select one set of instances and delete them, but choose to remove references rather than to trash the files. There’s actually only one set of physical files – so if you trash them, the other set of links might not work either.

At this point, you have changed the Core Data model, so your app will not be compatible with the old model on your device. There is a way around this with Core Data migrations, but that is a topic for another tutorial ;] For now, just delete the app off your device/simulator to get rid of any old files.

The next step is to build a view to create/edit tags associated with an instance of FailedBankDetails.

Contributors

Over 300 content creators. Join our team.