blob: 234c36a2b22fe6ed7f3e38738d11909fd1ad54c4 [file] [log] [blame]
Title: Relationships
<P>Relationships are special object properties that reference other &quot;related&quot; 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).</P>
<H3><A name="Relationships-ToOneRelationships"></A>To-One Relationships</H3>
<P>&quot;Get&quot; 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 &quot;set&quot; method:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">
Painting painting;
<SPAN class="code-comment">// obtain artist <SPAN class="code-keyword">for</SPAN> a given painting
</SPAN>Artist originalArtist = painting.getToArtist();
<SPAN class="code-comment">// replace with a <SPAN class="code-keyword">new</SPAN> artist
</SPAN>Artist newArtist = (Artist)context.newObject(Artist.class);
painting.setToArtist(newArtist);
<SPAN class="code-comment">// or remove Artist at all...
</SPAN><SPAN class="code-comment">// painting.setToArtist(<SPAN class="code-keyword">null</SPAN>);</SPAN>
</PRE>
</DIV></DIV>
<DIV class="panelMacro"><TABLE class="infoMacro"><COLGROUP><COL width="24"><COL></COLGROUP><TR><TD valign="top"><IMG src="http://cayenne.apache.org/docs/3.0/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></TD><TD>When adding or removing an object from any kind of relationship, Cayenne will locate and modify an existing reverse relationship as appropriate.</TD></TR></TABLE></DIV>
<H3><A name="Relationships-ToManyRelationships"></A>To-Many Relationships</H3>
<P>&quot;Get&quot; 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 &quot;collections&quot;, although strictly speaking Map is not a Collection in Java.</P>
<P>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 &quot;addTo...&quot; and &quot;removeFrom...&quot; methods:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">
Artist artist;
<SPAN class="code-comment">// obtain a list of paintings
</SPAN>List paintings = artist.getPaintingArray();
<SPAN class="code-comment">// remove the first painting
</SPAN><SPAN class="code-keyword">if</SPAN>(paintings.size() &gt; 0) {
Painting firstPainting = (Painting)paintings.get(0);
artist.removeFromPaintingArray(firstPainting);
}
<SPAN class="code-comment">// add a <SPAN class="code-keyword">new</SPAN> painting
</SPAN>Painting newPainting = (Painting)context.newObject(Painting.class);
artist.addToPaintingArray(newPainting);
</PRE>
</DIV></DIV>
<P>Not much difference in managing Map relationships. Let's assume that Artist's paintings are modeled as a map, keyed by painting name:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">
Artist artist;
<SPAN class="code-comment">// obtain a map of paintings
</SPAN>Map paintings = artist.getPaintingMap();
<SPAN class="code-comment">// lookup the painting
</SPAN>Painting girl = (Painting) paintings.get(<SPAN class="code-quote">&quot;Girl&quot;</SPAN>);
<SPAN class="code-comment">// remove the painting
</SPAN><SPAN class="code-keyword">if</SPAN>(girl != <SPAN class="code-keyword">null</SPAN>) {
artist.removeFromPaintingMap(girl);
}
<SPAN class="code-comment">// add a <SPAN class="code-keyword">new</SPAN> painting
</SPAN>Painting newPainting = (Painting)context.newObject(Painting.class);
<SPAN class="code-comment">// must set the key property BEFORE adding to relationship
</SPAN><SPAN class="code-comment">// unless the key is object id:
</SPAN>newPainting.setName(<SPAN class="code-quote">&quot;New Painting&quot;</SPAN>);
artist.addToPaintingMap(newPainting);
</PRE>
</DIV></DIV>
<P>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:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">
Painting girl = (Painting) paintings.get(<SPAN class="code-quote">&quot;Girl&quot;</SPAN>);
girl.setName(<SPAN class="code-quote">&quot;New Name&quot;</SPAN>);
...
<SPAN class="code-keyword">if</SPAN>(paintings.get(<SPAN class="code-quote">&quot;Girl&quot;</SPAN>) != <SPAN class="code-keyword">null</SPAN>) {
<SPAN class="code-comment">// still <SPAN class="code-keyword">true</SPAN>
</SPAN>}
<SPAN class="code-keyword">if</SPAN>(paintings.get(<SPAN class="code-quote">&quot;New Name&quot;</SPAN>) != <SPAN class="code-keyword">null</SPAN>) {
<SPAN class="code-comment">// still <SPAN class="code-keyword">false</SPAN>
</SPAN>}
...
<SPAN class="code-comment">// <SPAN class="code-keyword">this</SPAN> refreshes relationship Map keys as a side effect
</SPAN>girl.getObjectContext().commitChanges();
<SPAN class="code-keyword">if</SPAN>(paintings.get(<SPAN class="code-quote">&quot;Girl&quot;</SPAN>) != <SPAN class="code-keyword">null</SPAN>) {
<SPAN class="code-comment">// now <SPAN class="code-keyword">false</SPAN>
</SPAN>}
<SPAN class="code-keyword">if</SPAN>(paintings.get(<SPAN class="code-quote">&quot;New Name&quot;</SPAN>) != <SPAN class="code-keyword">null</SPAN>) {
<SPAN class="code-comment">// now <SPAN class="code-keyword">true</SPAN>
</SPAN>}
</PRE>
</DIV></DIV>
<P>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.</P>