Relationships are special object properties that reference other "related" objects. Semantically there are two types of relationships - to-one pointing to just a single DataObjects (e.g. Painting.toArtist), and to-many pointing to a collection of Persistent objects of the some distinct base type (e.g. Artist.paintingArray).
To-One Relationships
"Get" methods for to-one relationships return the target Persistent object. If the object is not in memory yet, it will be fetched on first access. Modifying to-one relationships is no different from modifying attributes - just a simple call to a "set" method:
Painting painting; // obtain artist for a given painting Artist originalArtist = painting.getToArtist(); // replace with a new artist Artist newArtist = (Artist)context.newObject(Artist.class); painting.setToArtist(newArtist); // or remove Artist at all... // painting.setToArtist(null);
When adding or removing an object from any kind of relationship, Cayenne will locate and modify an existing reverse relationship as appropriate. |
To-Many Relationships
"Get" methods for to-many relationships return various collections of Persistent objects. To-many relationships can be mapped as Lists (default), Collections, Sets or Maps. Below we may refer to all four types of mappings as "collections", although strictly speaking Map is not a Collection in Java.
Just like individual Persistent objects, relationship collections are also resolved on first access (e.g. when a user tries to read an element from a collection or obtains an Iterator). For modification there are special "addTo..." and "removeFrom..." methods:
Artist artist; // obtain a list of paintings List paintings = artist.getPaintingArray(); // remove the first painting if(paintings.size() > 0) { Painting firstPainting = (Painting)paintings.get(0); artist.removeFromPaintingArray(firstPainting); } // add a new painting Painting newPainting = (Painting)context.newObject(Painting.class); artist.addToPaintingArray(newPainting);
Not much difference in managing Map relationships. Let's assume that Artist's paintings are modeled as a map, keyed by painting name:
Artist artist; // obtain a map of paintings Map paintings = artist.getPaintingMap(); // lookup the painting Painting girl = (Painting) paintings.get("Girl"); // remove the painting if(girl != null) { artist.removeFromPaintingMap(girl); } // add a new painting Painting newPainting = (Painting)context.newObject(Painting.class); // must set the key property BEFORE adding to relationship // unless the key is object id: newPainting.setName("New Painting"); artist.addToPaintingMap(newPainting);
There's one caveat though - if an object property that is used as a map key changes, the object is remapped in the relationship only after the context is committed:
Painting girl = (Painting) paintings.get("Girl"); girl.setName("New Name"); ... if(paintings.get("Girl") != null) { // still true } if(paintings.get("New Name") != null) { // still false } ... // this refreshes relationship Map keys as a side effect girl.getObjectContext().commitChanges(); if(paintings.get("Girl") != null) { // now false } if(paintings.get("New Name") != null) { // now true }
Performance-wise, Maps have the most overhead of all collection options. Sets are somewhat slower than Lists or Collections (Collections are implemented as Lists internally). Considering that Cayenne Lists are internally managed as ordered Sets, and are not allowed to contain the same object more than once, you may want to avoid modeling relationships as Sets at all, unless the object public interface requirements warrant that.