| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title xmlns:d="http://docbook.org/ns/docbook">Chapter 6. Persistent Objects and ObjectContext</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 3.1 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 3.1"><link rel="home" href="index.html" title="Cayenne Guide"><link rel="up" href="cayenne-guide-part2.html" title="Part II. Cayenne Framework"><link rel="prev" href="starting-cayenne.html" title="Chapter 5. Starting Cayenne"><link rel="next" href="expressions.html" title="Chapter 7. Expressions"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-7036673-1']); |
| _gaq.push(['_trackPageview']); |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| </script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.3.1 (3.1)</th><th align="center">Chapter 6. Persistent Objects and ObjectContext</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="starting-cayenne.html">Prev</a> </td><th width="60%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Part II. Cayenne Framework</a></th><td width="20%" align="right"> <a accesskey="n" href="expressions.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 6. Persistent Objects and ObjectContext"><div class="titlepage"><div><div><h2 class="title"><a name="persistent-objects-objectcontext"></a>Chapter 6. Persistent Objects and ObjectContext</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="persistent-objects-objectcontext.html#objectcontext">ObjectContext</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#persistent-lifecycle">Persistent Object and its Lifecycle</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#persistent-operations">ObjectContext Persistence API</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#cayenne-helper-class">Cayenne Helper Class</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#objectcontext-nesting">ObjectContext Nesting</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#generic-persistent-objects">Generic Persistent Objects</a></span></dt><dt><span class="section"><a href="persistent-objects-objectcontext.html#transactions">Transactions</a></span></dt></dl></div><div class="section" title="ObjectContext"><div class="titlepage"><div><div><h2 class="title"><a name="objectcontext"></a>ObjectContext</h2></div></div></div><p>ObjectContext is an interface that users normally work with to access the database. It |
| provides the API to execute database operations and to manage persistent objects. A |
| context is obtained from the |
| ServerRuntime:</p><pre class="programlisting">ObjectContext context = runtime.getContext();</pre><p>The call above creates a new instance of ObjectContext that can access the database via this |
| runtime. ObjectContext is a single "work area" in Cayenne, storing persistent objects. |
| ObjectContext guarantees that for each database row with a unique ID it will contain at |
| most one instance of an object, thus ensuring object graph consistency between multiple |
| selects (a feature called "uniquing"). At the same time different ObjectContexts will |
| have independent copies of objects for each unique database row. This allows users to |
| isolate object changes from one another by using separate ObjectContexts.</p><p>These properties directly affect the strategies for scoping and sharing (or not |
| sharing) ObjectContexts. Contexts that are only used to fetch objects from the database |
| and whose objects are never modified by the application can be shared between mutliple |
| users (and multiple threads). Contexts that store modified objects should be accessed |
| only by a single user (e.g. a web application user might reuse a context instance |
| between multiple web requests in the same HttpSession, thus carrying uncommitted changes |
| to objects from request to request, until he decides to commit or rollback them). Even |
| for a single user it might make sense to use mutliple ObjectContexts (e.g. |
| request-scoped contexts to allow concurrent requests from the browser that change and |
| commit objects independently).</p><p>ObjectContext is serializable and does not permanently hold to any of the application |
| resources. So it does not have to be closed. If the context is not used anymore, it |
| should simply be allowed to go out of scope and get garbage collected, just like any |
| other Java object.</p></div><div class="section" title="Persistent Object and its Lifecycle"><div class="titlepage"><div><div><h2 class="title"><a name="persistent-lifecycle"></a>Persistent Object and its Lifecycle</h2></div></div></div><p>Cayenne can persist Java objects that implement <code class="code">org.apache.cayenne.Persistent</code> |
| interface. Generally persistent classes are generated from the model as described above, |
| so users do not have to worry about superclass and property implementation details. </p><p>Persistent interface provides access to 3 persistence-related properties - objectId, |
| persistenceState and objectContext. All 3 are initialized by Cayenne runtime framework. |
| Application code should not attempt to change them them. However it is allowed to read |
| them, which provides valuable runtime information. E.g. ObjectId can be used for quick |
| equality check of 2 objects, knowing persistence state would allow highlighting changed |
| objects, etc.</p><p>Each persistent object belongs to a single ObjectContext, and can be in one of the following |
| persistence states (as defined in <code class="code">org.apache.cayenne.PersistenceState</code>) |
| :</p><table frame="void" id="d0e1062"><caption>Table 6.1. Persistence States</caption><col width="16%"><col width="84%"><tbody><tr> |
| <td>TRANSIENT</td> |
| <td>The object is not registered with an ObjectContext and will not be |
| persisted.</td> |
| </tr><tr> |
| <td>NEW</td> |
| <td>The object is freshly registered in an ObjectContext, but has not been |
| saved to the database yet and there is no matching database row.</td> |
| </tr><tr> |
| <td>COMMITTED</td> |
| <td>The object is registered in an ObjectContext, there is a row in the |
| database corresponding to this object, and the object state corresponds |
| to the last known state of the matching database row.</td> |
| </tr><tr> |
| <td>MODIFIED</td> |
| <td>The object is registered in an ObjectContext, there is a row in the |
| database corresponding to this object, but the object in-memory state |
| has diverged from the last known state of the matching database |
| row.</td> |
| </tr><tr> |
| <td>HOLLOW</td> |
| <td>The object is registered in an ObjectContext, there is a row in the |
| database corresponding to this object, but the object state is unknown. |
| Whenever an application tries to access a property of such object, |
| Cayenne attempts reading its values from the database and "inflate" the |
| object, turning it to COMMITED.</td> |
| </tr><tr> |
| <td>DELETED</td> |
| <td>The object is registered in an ObjectContext and has been marked for |
| deletion in-memory. The corresponding row in the database will get |
| deleted upon ObjectContext commit, and the object state will be turned |
| into TRANSIENT.</td> |
| </tr></tbody></table></div><div class="section" title="ObjectContext Persistence API"><div class="titlepage"><div><div><h2 class="title"><a name="persistent-operations"></a>ObjectContext Persistence API</h2></div></div></div><p>One of the first things users usually want to do with an ObjectContext is to select |
| some objects from a database. This is done by calling "<span class="italic">performQuery</span>" |
| method:</p><pre class="programlisting">SelectQuery query = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> SelectQuery(Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| List<Artist> artists = context.performQuery(query);</pre><p>We'll |
| discuss queries in some detail in the following chapters. The example above is |
| self-explanatory - we create a SelectQuery that matches all Artist objects present in |
| the database, and then call "performQuery", getting a list of Artist objects.</p><p>Some queries can be quite complex, returning multiple result sets or even updating the |
| database. For such queries ObjectContext provides "<span class="italic">performGenericQuery</span>"method. While not nearly as commonly-used as |
| "performQuery", it is nevertheless important in some situations. |
| E.g.:</p><pre class="programlisting">Collection<Query> queries = ... <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// multiple queries that need to be run together</span> |
| QueryChain query = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> QueryChain(queries); |
| |
| QueryResponse response = context.performGenericQuery(query);</pre><p>An application might modify selected objects. E.g.:</p><pre class="programlisting">Artist selectedArtist = artists.get(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>); |
| selectedArtist.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Dali"</span>);</pre><p>The first time the object property is changed, the object's state is automatically set |
| to "MODIFIED" by Cayenne. Cayenne tracks all in-memory changes until a user calls |
| "<span class="italic">commitChanges</span>":</p><pre class="programlisting">context.commitChanges();</pre><p>At |
| this point all in-memory changes are analyzed and a minimal set of SQL statements is |
| issued in a single transaction to synchronize the database with the in-memory state. In |
| our example "commitChanges" commits just one object, but generally it can be any number |
| of objects. </p><p>If instead of commit, we wanted to reset all changed objects to the previously |
| committed state, we'd call <span class="emphasis"><em>rollbackChanges</em></span> |
| instead:</p><pre class="programlisting">context.rollbackChanges();</pre><p>"<span class="italic">newObject</span>" method call creates a persistent object |
| and sets its state to |
| "NEW":</p><pre class="programlisting">Artist newArtist = context.newObject(Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| newArtist.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Picasso"</span>);</pre><p>It will only exist in memory until "commitChanges" is issued. On commit Cayenne might |
| generate a new primary key (unless a user set it explicitly, or a PK was inferred from a |
| relationship) and issue an INSERT SQL statement to permanently store the object.</p><p><span class="emphasis"><em>deleteObjects</em></span> method takes one or more Persistent objects and |
| marks them as |
| "DELETED":</p><pre class="programlisting">context.deleteObjects(artist1); |
| context.deleteObjects(artist2, artist3, artist4);</pre><p>Additionally |
| "deleteObjects" processes all delete rules modeled for the affected objects. This may |
| result in implicitly deleting or modifying extra related objects. Same as insert and |
| update, delete operations are sent to the database only when "commitChanges" is called. |
| Similarly "rollbackChanges" will undo the effect of "newObject" and |
| "deleteObjects".</p><p><span class="emphasis"><em>localObject</em></span> returns a copy of a given persistent object that is |
| "local" to a given ObjectContext:</p><p>Since an application often works with more than one context, "localObject" is a rather |
| common operation. E.g. to improve performance a user might utilize a single shared |
| context to select and cache data, and then occasionally transfer some selected objects |
| to another context to modify and commit |
| them:</p><pre class="programlisting">ObjectContext editingContext = runtime.getContext(); |
| Artist localArtist = editingContext.localObject(artist);</pre><p>Often an appliction needs to inspect mapping metadata. This information is stored in |
| the EntityResolver object, accessible via the |
| ObjectContext:</p><pre class="programlisting">EntityResolver resolver = objectContext.getEntityResolver();</pre><p>Here we discussed the most commonly used subset of the ObjectContext API. There are |
| other useful methods, e.g. those allowing to inspect registered objects state en bulk, |
| etc. Check the latest JavaDocs for details.</p></div><div class="section" title="Cayenne Helper Class"><div class="titlepage"><div><div><h2 class="title"><a name="cayenne-helper-class"></a>Cayenne Helper Class</h2></div></div></div><p>There is a useful helper class called "Cayenne" (fully-qualified name |
| <code class="code">"org.apache.cayenne.Cayenne"</code>) that builds on ObjectContext API to |
| provide a number of very common operations. E.g. get a primary key (most entities do not |
| model PK as an object property) |
| :</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">long</span> pk = Cayenne.longPKForObject(artist);</pre><p>It also provides the reverse operation - finding an object given a known |
| PK:</p><pre class="programlisting">Artist artist = Cayenne.objectForPK(context, Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">34579</span>);</pre><p>If a query is expected to return 0 or 1 object, Cayenne helper class can be used to find |
| this object. It throws an exception if more than one object matched the |
| query:</p><pre class="programlisting">Artist artist = (Artist) Cayenne.objectForQuery(context, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> SelectQuery(Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>));</pre><p>Feel free to explore Cayenne class API for other useful methods.</p></div><div class="section" title="ObjectContext Nesting"><div class="titlepage"><div><div><h2 class="title"><a name="objectcontext-nesting"></a>ObjectContext Nesting</h2></div></div></div><p>In all the examples shown so far an ObjectContext would directly connect to a database |
| to select data or synchronize its state (either via commit or rollback). However another |
| context can be used in all these scenarios instead of a database. This concept is called |
| ObjectContext "nesting". Nesting is a parent/child relationship between two contexts, |
| where child is a nested context and selects or commits its objects via a parent. </p><p>Nesting is useful to create isolated object editing areas (child contexts) that need |
| to all be committed to an intermediate in-memory store (parent context), or rolled back |
| without affecting changes already recorded in the parent. Think cascading GUI dialogs, |
| or parallel AJAX requests coming to the same session.</p><p>In theory Cayenne supports any number of nesting levels, however applications should |
| generally stay with one or two, as deep hierarchies will most certainly degrade the |
| performance of the deeply nested child contexts. This is due to the fact that each |
| context in a nesting chain has to update its own objects during most operations. </p><p>Cayenne ROP is an extreme case of nesting when a child context is located in a |
| separate JVM and communicates with its parent via a web service. ROP is discussed in |
| details in the following chapters. Here we concentrate on the same-VM nesting.</p><p>To create a nested context, use an instance of ServerRuntime, passing it the desired |
| parent:</p><pre class="programlisting">ObjectContext parent = runtime.getContext(); |
| ObjectContext nested = runtime.getContext((DataChannel) parent);</pre><p>From |
| here a nested context operates just like a regular context (you can perform queries, |
| create and delete objects, etc.). The only difference is that commit and rollback |
| operations can either be limited to synchronization with the parent, or cascade all the |
| way to the |
| database:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// merges nested context changes into the parent context</span> |
| nested.commitChangesToParent(); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// regular 'commitChanges' cascades commit through the chain </span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// of parent contexts all the way to the database</span> |
| nested.commitChanges();</pre><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// unrolls all local changes, getting context in a state identical to parent</span> |
| nested.rollbackChangesLocally(); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// regular 'rollbackChanges' cascades rollback through the chain of contexts </span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// all the way to the topmost parent</span> |
| nested.rollbackChanges();</pre></div><div class="section" title="Generic Persistent Objects"><div class="titlepage"><div><div><h2 class="title"><a name="generic-persistent-objects"></a>Generic Persistent Objects</h2></div></div></div><p>As described in the CayenneModeler chapter, Cayenne supports mapping of completely |
| generic classes to specific entities. Although for conveniece most applications should |
| stick with entity-specific class mappings, the generic feature offers some interesting |
| possibilities, such as creating mappings completely on the fly in a running application, |
| etc.</p><p>Generic objects are first class citizens in Cayenne, and all common persistent |
| operations apply to them as well. There are some pecularities however, described |
| below.</p><p>When creating a new generic object, either cast your ObjectContext to DataContext |
| (that provides "newObject(String)" API), or provide your object with an explicit |
| ObjectId:</p><pre class="programlisting">DataObject generic = ((DataContext) context).newObject(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"GenericEntity"</span>);</pre><pre class="programlisting">DataObject generic = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> CayenneDataObject(); |
| generic.setObjectId(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> ObjectId(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"GenericEntity"</span>)); |
| context.registerNewObject(generic);</pre><p>SelectQuery |
| for generic object should be created passing entity name String in constructor, instead |
| of a Java |
| class:</p><pre class="programlisting">SelectQuery query = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> SelectQuery(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"GenericEntity"</span>);</pre><p>Use |
| DataObject API to access and modify properties of a generic |
| object:</p><pre class="programlisting">String name = (String) generic.readProperty(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"name"</span>); |
| generic.writeProperty(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"name"</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"New Name"</span>);</pre><p>This |
| is how an application can obtain entity name of a generic |
| object:</p><pre class="programlisting">String entityName = generic.getObjectId().getEntityName();</pre></div><div class="section" title="Transactions"><div class="titlepage"><div><div><h2 class="title"><a name="transactions"></a>Transactions</h2></div></div></div><p>Considering how much attention is given to managing transactions in most other ORMs, |
| transactions have been conspicuously absent from the ObjectContext discussion till now. |
| The reason is that transactions are seamless in Cayenne in all but a few special cases. |
| ObjectContext is an in-memory container of objects that is disconnected from the |
| database, except when it needs to run an operation. So it does not care about any |
| surrounding transaction scope. Sure enough all database operations are transactional, so |
| when an application does a commit, all SQL execution is wrapped in a database |
| transaction. But this is done behind the scenes and is rarely a concern to the |
| application code.</p><p>Two cases where transactions need to be taken into consideration are container-managed |
| and application-managed transactions. </p><p>If you are using an EJB container (or some other JTA environment), you'll likely need |
| to switch Cayenne runtime into "external transactions mode". This is either done in the |
| Modeler (check DataDomain > 'Container-Managed Transactions' checkbox), or in the |
| code:</p><pre class="programlisting">runtime.getDataDomain().setUsingExternalTransactions(true);</pre><p>In |
| this case Cayenne assumes that JDBC Connections obtained by runtime whenever that might |
| happen are all coming from a transactional DataSource managed by the container. In this |
| case Cayenne does not attempt to commit or rollback the connections, leaving it up to |
| the container to do that when appropriate.</p><p>In the second scenario, an application might need to define its own transaction scope |
| that spans more than one Cayenne operation. E.g. two sequential commits that need to be |
| rolled back together in case of failure. This can be done with an explicit thread-bound |
| transaction that surrounds a set of operations. Application is responsible for |
| committing or rolling it |
| back:</p><pre class="programlisting">Transaction tx = runtime.getDataDomain().createTransaction(); |
| Transaction.bindThreadTransaction(tx); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">try</span> { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// commit one or more contexts</span> |
| context1.commitChanges(); |
| context2.commitChanges(); |
| .... |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// after changing some objects in context1, commit again</span> |
| context1.commitChnages(); |
| .... |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// if no failures, commit</span> |
| tx.commit(); |
| } |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">catch</span> (Exception ex) { |
| tx.setRollbackOnly(); |
| } |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">finally</span> { |
| Transaction.bindThreadTransaction(null); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">if</span> (tx.getStatus() == Transaction.STATUS_MARKED_ROLLEDBACK) { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">try</span> { |
| tx.rollback(); |
| } |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">catch</span> (Exception rollbackEx) { |
| } |
| } |
| } </pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="starting-cayenne.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="expressions.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 5. Starting Cayenne </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 7. Expressions</td></tr></table></div></body></html> |