Cocoa for Scientists (Part XXII): Core Data Models

Author: Drew McCormack
Web Site: www.maccoremac.com

In Mac OS X 10.4 (Tiger), Apple introduced the last piece of a Cocoa puzzle: Core Data. In 10.3 (Panther), Apple added Cocoa Bindings, which allow an application’s views to automatically synchronize with its internal data. But it was still largely up to the developer to organize a program’s data, or model layer: Cocoa didn’t give you much for free. Core Data changed all that in Tiger, making it relatively easy to come up with a model for your data, and reaping many benefits in the process.

In the coming weeks, we are going to delve into a simple scientific Core Data application. The first couple of tutorials will cover the basics, and in the last one, we’ll look at what Leopard has added to the mix.

An ‘Object-Graph Management and Persistence Framework’, for Lack of a Better Phrase

So what exactly is Core Data? It’s probably better to begin by stating what it is not. It is a common misconception that Core Data is a database abstraction layer, designed to make it easy to store data in a database from a Cocoa application. Although Core Data can work with a database, it is not a general library for building database-backed software. For that, you are better off with something like WebObjects’ Enterprise Objects Framework.

If Core Data is not a general purpose database abstraction framework, what exactly is it? Apple’s Docs refer to it as an ‘object-graph management and persistence framework’. Wordy, to be sure, but what does it mean? Basically, every program defines a number of model classes to store its data, and save it to disk. Core Data provides a way to explicitly define the relationships between various classes of objects, and how these relationships should be handled. With this information, Core Data can manage the objects for you, rather than requiring you to write a lot of code to do it. For example, you might have a class like Airplane that contains references to objects of the class Wing. You could setup your Core Data model such that whenever an Airplane is deleted, its Wings are also automatically deleted.

That covers the ‘object-graph management’ part, but what about the ‘persistence’ bit? Because Core Data knows how the various model classes — or entities as they are most accurately known — relate to each other, it can also figure out how to store them on disk. So when you come up with an model for Core Data, you basically don’t have to worry any more about how to read and write from disk — Core Data will do it automatically. What’s more, it can write the same object graph to disk in various formats, including a very fast SQLite-based database format, and a human-readable XML format.

Creating a Core Data Project

The model you design for Core Data is called a managed object model; it consists of a number of entities — which are similar to, but not the same as, classes — and relationships between the entities.

In this series of tutorials we are going to build an application that allows you manage a personal database of molecules. To do this, you first need to create a new project in Xcode.

  1. Choose File > New Project…
  2. In the Application group, choose ‘Core Data Application’, and click Next.
  3. Enter the project name ‘Molecular Core’.
  4. Select where on disk you want to have the project, and click Finish.

You design your managed object model using a graphical tool in Xcode called the data modeler. The models themselves are stored in data model file; Xcode creates such a file when you start a new Core Data project. To bring up the data modeler, select the file Molecular_Core_DataModel.xcdatamodel, which is in the Models group in the Groups & Files source list on the left of the Xcode project window. (You may need to drag up the split view on the right to see the data modeler.)

The Data Modeler

Designing a Managed Object Model

We will now start to add entities and define relationships inside the modeler. To add a new entity, click the + button at the bottom of the entity browser on the left of the data modeler. An entity box should appear in the layout view below. Double click the title bar of this box to change its title to ‘Atom’.

The Atom entity will store information about a particular atom in a molecule, such as its position in space. Like classes, entities can store data, which are known as attributes. In order to add attributes for the position of the Atom, follow this procedure:

  1. With the Atom box still selected, click and hold the + button under the Property list to the right of the Entity list.
  2. Select Add Attribute from the popup list. A new attribute should appear in the Atom box.
  3. With the attribute still selected, change its name to ‘positionX’ in the inspector pane on the far right of the model browser.
  4. Also make the following changes in the inspector:
    • Make sure ‘Optional’ is checked.
    • Choose ‘Double’ from the Type popup button.
    • Enter 0 in the Default Value field.

Setting the Position Attribute.

To create position attributes for the y and z dimensions, select the positionX attribute in the Atom box, copy it, and paste it twice. Change the names of the new attributes to positionY and positionZ. Save your changes.

Each atom has a species, or more precisely, a chemical element. One chemical element can apply to many atoms, so we need to define a new Element entity, and then relate the Atom entity to the Element entity by a one-to-many relationship.

  1. Add a new entity using the + button under the Entity list on the left.
  2. In the inspector on the right, fill in the name ‘Element’.
  3. Add a new attribute by clicking the + button under the Property list, and selecting ‘Add Attribute’ from the list.
  4. In the inspector, make the following changes for the new attribute:
    • Enter the name ‘symbol’.
    • Uncheck ‘Optional’.
    • Select ‘String’ in the Type popup button.
    • Enter 1 for the Min Length, and 3 for the Max Length.

If you remember your high-school chemistry, most of this should make sense: Each chemical element has a symbol in the periodic table of elements; the symbol is a string between 1 and 3 characters in length.

Adding Relationships

Now we need to relate the Atom entity to the Element entity.

  1. Select the Atom box.
  2. Click on the + button under the Property list, and select ‘Add Relationship’ from the popup menu.
  3. In the inspector, fill in the name ‘element’ for the relationship, and uncheck ‘Optional’.
  4. Choose Element from the Destination popup button.
  5. Add a new relationship called ‘atoms’ to the Element entity. Set it up as follows:
    • Leave ‘Optional’ checked.
    • Select ‘Atom’ from the Destination popup button.
    • Choose ‘element’ from the Inverse popup button.
    • Check the ‘To-Many Relationship’ checkbox.
    • Choose ‘Cascade’ from the Delete Rule popup button.

Creating a Relationship.

You’re probably wondering what all this means, so let’s go through the meaning of the various settings in the Relationship inspector pane.

  • The name is used to access the relationship in the program.
  • The Optional checkbox indicates whether a particular relationship can be empty. Because an Atom must always have an Element, we set the element relationship to be non-optional. The reverse, however, is not true: an Element may have no atoms associated with it, so the relationship atoms is optional.
  • The Transient checkbox indicates whether or not a particular relationship or attribute should be stored (ie, be persistent). In this case, we want everything to be stored, so Transient is always left unchecked.
  • The Destination popup should be self explanatory: it is the target entity of the relationship.
  • The Inverse popup allows you to indicate that two particular relationships are actually the inverse of one another. This is the case for element and atoms.
  • The To-Many Relationship checkbox indicates a relationship is one-to-many or many-to-many.
  • Min Count and Max Count allow you to restrict the number of objects in a particular relationship.
  • The Delete Rule is somewhat involved: it relates to what should happen to any related objects when a particular object gets deleted. The most common cases are ‘Nullify’, which means to remove the deleted object from the inverse relationship of any related object, and ‘Cascade’, which means to delete any related objects.

This takes a while to sink in, but it all makes sense when you get used to it.

To finish off the model, add a new Entity called ‘Molecule’. A Molecule should have a non-optional name attribute of String type, and a one-to-many relationship to Atom called ‘atoms’, because an atom can be in only one molecule, while a molecule can have many atoms. The inverse relationship (on Atom) should be called ‘molecule’.

The settings for the atoms relationship on the Molecule entity should be: optional, to-many, and with the Cascade delete rule. (If you delete a molecule, it implies that all its atoms should also be deleted, hence the ‘Cascade’ setting.)

The settings for the molecule relationship on the Atom entity should be: non-optional, to-one, and with the Nullify delete rule. (If you delete an atom, it should be removed from its molecule, but the molecule should not be deleted. That’s what ‘Nullify’ does.)

The final model should look something like the figure below.

The Final Model.

Next Time

Molecular Core doesn’t do much yet, but next time we will add some interface to it, and make it a real working app. You’ll be surprised just how little code you need to do that. In the meantime, you can download the project file for this week.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Nice!

Wow! What a great article! I look forward to the next installment! A few things (IMHO):

(a) WO's EOF is (now) Java only, and I don't think it is necessarily the best for high-volume data, like a lot of scientific data is, because of its caches and complexity. It is good for complex data, like stuff with a lot of relations (a.k.a. business logic). It can be a bit difficult to program and opens up a whole other can of worms. Having programmed with it in EOF 1.0 (before the web was invented) in desktop apps I do miss it on the desktop!

(b) When I use Core Data I find I have to use it sparingly because the data-related schema can be "corrupted" by side-effects like adding entities exclusive to the user interface that I might not build into a basic data model.

(c) The Tiger version of Core Data has a few weird aspects like wanting inverse relationships even though I don't want an inverse in the schema myself.

(d) Core Data is really a great tool, but there are some behavior issues that are hard to know about such as assigning a managed object context programmatically v.s. a binding. They produce different results sometimes when it is not expected.

(e) Core Data is fun to program in, especially if you can do it on a 30 inch screen!

thanks!-

-lance
lbland@vvi.com

Core Data Comments

Hi Lance,

(a) I agree about EOF: it is a web dev framework, not a scientific one. Does anyone know of a good database framework targeted at science? There are things like HDF and netCDF, which are database-like, but not exactly the same.

(b) Regarding interface entities in the model: I believe you can very easily split up a model, and simply import them all (merged) to use them. I guess if you have stuff that is only for the interface, you could split this off into a separate model file.

(c) Yes, inverse relationships are a bit strange. To anyone new to Core Data, you should basically always use inverse relationships in your models, whether you think you need them or not. The reason is that otherwise you have to be very careful about explicitly deleting objects that are no longer needed --- CD won't do it for you.

(d) There are lots of intricacies, to be sure.

(e) Yeah, building models is fun, and it can save you a lot of code. It gives you some headaches while you are learning it though.

Drew

---------------------------
Drew McCormack
http://www.maccoremac.com
http://www.macanics.net
http://www.macresearch.org

Any Database Frameworks?

Are they any database frameworks available for building database desktop applications - commercial or opensource ?