blob: 35b07a4a7c6cbb8a3259bddf9f75588ae3f5840e [file] [log] [blame]
Title: Nested Contexts
<P>One of the goals of the ObjectContext is to provide an isolated area where local object changes can be performed without affecting other similar areas or the underlying storage. At some point in time users would either commit changes to the underlying storage or undo them (roll them back). </P>
<P>If a DataContext is directly attached to the DataDomain, a call to <TT>DataContext.commitChanges()</TT> results in changes written to the database. On the other hand if DataContext's direct parent in the access stack is not a DataDomain, but another DataContext, changes can be saved to the parent without saving them to the database. Such child context is often called &quot;nested&quot;.</P>
<P>Same thing is true when ObjectContext is used via ROP. Committing changes to a nested ROP ObjectContext (CayenneContext) locally will not result in sending data to a server.</P>
<DIV class="panelMacro"><TABLE class="noteMacro"><COLGROUP><COL width="24"><COL></COLGROUP><TR><TD valign="top"><IMG src="http://cayenne.apache.org/docs/3.0/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></TD><TD><B>ROP</B><BR>Nested contexts are available in Cayenne ROP (three tier) only from version 3.0M6.</TD></TR></TABLE></DIV>
<P>Nested contexts are useful in many situations, such as nested UI dialogs, complicated workflows, etc.</P>
<H3><A name="NestedContexts-CreatingNestedContexts"></A>Creating Nested Contexts</H3>
<DIV class="panelMacro"><TABLE class="noteMacro"><COLGROUP><COL width="24"><COL></COLGROUP><TR><TD valign="top"><IMG src="http://cayenne.apache.org/docs/3.0/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></TD><TD><B>Deprecation</B><BR>Since 3.0M6 a new method, <TT>ObjectContext.createChildContext()</TT> was introduced, so <TT>DataContext.createChildDataContext()</TT> is now deprecated. Please update your code properly.</TD></TR></TABLE></DIV>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">ObjectContext parent = ...
ObjectContext child = context.createChildContext();</PRE>
</DIV></DIV>
<P><TT>child</TT> object will be instance of the same class, as <TT>parent</TT> is - DataContext or CayenneContext.</P>
<P>When creating a nested DataContext, note that if there was a DataContextFactory configured for the DataDomain at the top of the context hierarchy, such factory will be used internally by <TT>createChildDataContext</TT> method. Also child DataContext inherits parent's <TT>&quot;ValidatingObjectsOnCommit&quot;</TT> property.</P>
<H3><A name="NestedContexts-UsingNestedContexts"></A>Using Nested Contexts</H3>
<P>A nested context does everything a parent context can do, i.e. perform queries, register new objects, delete objects, etc. A specific behavior is the ability to choose between a cascading or one-level commit or rollback.</P>
<P>Regular <TT>&quot;commitChanges&quot;</TT> call does a cascading commit through the stack of parents all the way to the database:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">child.commitChanges();</PRE>
</DIV></DIV>
<P>However it is possible to commit to parent, without triggering a DB commit:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">child.commitChangesToParent();</PRE>
</DIV></DIV>
<P>Same thing with rollback, <TT>&quot;rollbackChanges&quot;</TT> does a cascading rollback:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">child.rollbackChanges();</PRE>
</DIV></DIV>
<P>While <TT>&quot;rollbackChangesLocally&quot;</TT> only affects the nested context, and not even sent to the parent:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">child.rollbackChangesLocally();</PRE>
</DIV></DIV>
<P>From the child context, you may want to get a reference to the parent context. Use child.getChannel() to get the parent context, and if called from the top level context context.getChannel() will return the DataDomain.</P>
<H3><A name="NestedContexts-NestedContextsPerformance"></A>Nested Contexts Performance</H3>
<P>All cascading operations (such as a select query or a cascading update) initiated by a nested context will have to travel through the stack of parent contexts, incurring certain delay at each stack level. The delay is due to the fact that each context has to update its own objects during most operations. So nesting should only be used when application specifics require to do so. Also nesting of more than a few levels should be avoided.</P>