blob: b5527317949f63aa7833f9fc8f13ec7590a97ed8 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.3">
<link rel="apple-touch-icon" sizes="180x180" href="/img/favicon/apple-touch-icon-04cb17e028.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon/favicon-32x32-12431ee8eb.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16-4f316e4d55.png">
<link rel="manifest" href="/img/favicon/manifest-65e6aaa49e.json">
<link rel="mask-icon" href="/img/favicon/safari-pinned-tab-558c1991b1.svg" color="#dc5656">
<link rel="shortcut icon" href="/img/favicon/favicon-6cef91375b.ico">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/img/favicon/mstile-144x144-34e7696278.png">
<meta name="msapplication-config" content="/img/favicon/browserconfig-82ff158058.xml">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="https://cayenne.apache.org/css/styles-9ee2e6e330.css"/>
<script src="https://cayenne.apache.org/js/bundle-c0e6356367.js"></script>
<title>Cayenne Guide 5.0 · Persistent Objects and ObjectContext &middot; Apache Cayenne</title>
</head>
<body class="cd-head">
<header class="page-header">
<nav id="topbar" class="bg-dark" aria-label="breadcrumb" role="navigation">
<ul class="breadcrumb breadcrumb-sm breadcrumb-dark container mb-0">
<li class="breadcrumb-item dropdown">
<a class="dropdown-toggle text-nowrap pr-1" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="mw-15px mr-1" src="/img/feather-641aa69d09.svg" />Apache Software Foundation</a>
<div class="dropdown-menu rounded-0" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="https://www.apache.org">Apache Homepage</a>
<a class="dropdown-item" href="https://www.apache.org/licenses/">License</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<a class="dropdown-item" href="https://www.apache.org/security/">Security</a>
<a class="dropdown-item" href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy</a>
<a class="ml-1 mt-1 acevent" data-format="wide" data-mode="dark" data-width="120"></a>
</div>
</li>
</ul>
</nav>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="https://cayenne.apache.org/">
<img src="/img/logo_mono_full-d7a19eef61.svg" alt="Apache Cayenne" />
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainMenu">
<ul class="navbar-nav mt-3 mt-lg-0 mr-auto">
<li class="nav-item">
<a class="nav-link" href="/download/">DOWNLOAD</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/docs/4.2/getting-started-guide/">DOCUMENTATION</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about/support/">SUPPORT</a>
</li>
</ul>
<ul class="navbar-nav flex-row justify-content-center mt-2 mt-lg-0 mb-2 mb-lg-0 " id="social-links-menu">
<li class="nav-item d-flex">
<a class="nav-link d-flex justify-content-center align-items-center" href="https://github.com/apache/cayenne">
<img src="/img/icon_octocat_stars-c24dac94b8.svg" alt="GitHub" />
</a>
</li>
<li class="nav-item d-flex">
<a class="nav-link d-flex justify-content-center align-items-center" href="https://twitter.com/ApacheCayenne">
<img src="/img/icon_twitter-220a129d14.svg" alt="Twitter" />
</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main>
<div class="cd-top-sidebar bb">
<div class="container">
<div class="row no-gutters">
<div class="col-12 col-lg-4 col-xl-3 br cd-sidebar1">
<ul class="nav" role="tablist">
<li class="nav-item dropdown mw-100">
<a class="nav-link dropdown-toggle text-truncate" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
Cayenne Version 5.0
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="/docs/5.0/cayenne-guide/">Version 5.0 (Alpha)</a><a class="dropdown-item" href="/docs/4.2/getting-started-guide/">Version 4.2 (Stable)</a><a class="dropdown-item" href="/docs/4.1/getting-started-guide/">Version 4.1 (Stable)</a><a class="dropdown-item" href="/docs/4.0/getting-started-guide/">Version 4.0 (Aging)</a><a class="dropdown-item" href="/docs/3.1/getting-started-guide/">Version 3.1 (Legacy)</a>
</div>
</li>
</ul>
</div>
<div class="col-12 col-lg-8 col-xl-9"> </div>
</div>
</div>
</div>
<div class="container">
<div class="row no-gutters ">
<div class="col-12 col-lg-4 col-xl-3 br py-2 bg-gray-100 cd-sidebar">
<div class="tab-content" id="cd-docs-nav">
<div class="cd-toc-item">
<span class="cd-toc-link active">Cayenne Guide 5.0</span><div id="toc" class="toc toc-side">
<div id="toctitle">
Table of Contents
</div>
<ul class="sectlevel1 nav">
<li><a href="/docs/5.0/cayenne-guide/object-relational-mapping-with-cayenne" class="nav-link" id="object-relational-mapping-with-cayenne">1. Object Relational Mapping with Cayenne</a>
<ul class="sectlevel2 nav">
<li><a href="/docs/5.0/cayenne-guide/setup" class="nav-link" id="setup">1.1. Setup</a></li>
<li><a href="/docs/5.0/cayenne-guide/cayenne-mapping-structure" class="nav-link" id="cayenne-mapping-structure">1.2. Cayenne Mapping Structure</a></li>
<li><a href="/docs/5.0/cayenne-guide/cayenne-modeler" class="nav-link" id="cayenne-modeler">1.3. CayenneModeler Application</a></li>
</ul></li>
<li><a href="/docs/5.0/cayenne-guide/cayenne-framework" class="nav-link" id="cayenne-framework">2. Cayenne Framework</a>
<ul class="sectlevel2 nav">
<li><a href="/docs/5.0/cayenne-guide/including-cayenne-in-project" class="nav-link" id="including-cayenne-in-project">2.1. Including Cayenne in a Project</a></li>
<li><a href="/docs/5.0/cayenne-guide/starting-cayenne" class="nav-link" id="starting-cayenne">2.2. Starting Cayenne</a></li>
<li><a href="/docs/5.0/cayenne-guide/persistent-objects-objectcontext" class="nav-link" id="persistent-objects-objectcontext">2.3. Persistent Objects and ObjectContext</a></li>
<li><a href="/docs/5.0/cayenne-guide/expressions" class="nav-link" id="expressions">2.4. Expressions</a></li>
<li><a href="/docs/5.0/cayenne-guide/orderings" class="nav-link" id="orderings">2.5. Orderings</a></li>
<li><a href="/docs/5.0/cayenne-guide/queries" class="nav-link" id="queries">2.6. Queries</a></li>
<li><a href="/docs/5.0/cayenne-guide/lifecycle-events" class="nav-link" id="lifecycle-events">2.7. Lifecycle Events</a></li>
<li><a href="/docs/5.0/cayenne-guide/performance-tuning" class="nav-link" id="performance-tuning">2.8. Performance Tuning</a></li>
<li><a href="/docs/5.0/cayenne-guide/customizing-cayenne-runtime" class="nav-link" id="customizing-cayenne-runtime">2.9. Customizing Cayenne Runtime</a></li>
</ul></li>
<li><a href="/docs/5.0/cayenne-guide/db-first-flow" class="nav-link" id="db-first-flow">3. DB-First Flow</a>
<ul class="sectlevel2 nav">
<li><a href="/docs/5.0/cayenne-guide/re-introduction" class="nav-link" id="re-introduction">3.1. Introduction</a></li>
<li><a href="/docs/5.0/cayenne-guide/re-filtering" class="nav-link" id="re-filtering">3.2. Filtering</a></li>
<li><a href="/docs/5.0/cayenne-guide/re-relationships-loading-control" class="nav-link" id="re-relationships-loading-control">3.3. Other Settings</a></li>
<li><a href="/docs/5.0/cayenne-guide/re-modeler" class="nav-link" id="re-modeler">3.4. Reverse Engineering in Cayenne Modeler</a></li>
</ul></li>
<li><a href="/docs/5.0/cayenne-guide/additional-modules" class="nav-link" id="additional-modules">4. Additional Modules</a>
<ul class="sectlevel2 nav">
<li><a href="/docs/5.0/cayenne-guide/ext-cache-invalidation" class="nav-link" id="ext-cache-invalidation">4.1. Cache Invalidation Extension</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-commit-log" class="nav-link" id="ext-commit-log">4.2. Commit log extension</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-crypto" class="nav-link" id="ext-crypto">4.3. Crypto extension</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-jcache" class="nav-link" id="ext-jcache">4.4. JCache integration</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-project-compatibility" class="nav-link" id="ext-project-compatibility">4.5. Project compatibility extension</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-velocity" class="nav-link" id="ext-velocity">4.6. Apache Velocity Extension</a></li>
<li><a href="/docs/5.0/cayenne-guide/ext-osgi" class="nav-link" id="ext-osgi">4.7. Cayenne OSGI extension</a></li>
</ul></li>
<li><a href="/docs/5.0/cayenne-guide/build_tools" class="nav-link" id="build_tools">5. Build Tools</a>
<ul class="sectlevel2 nav">
<li><a href="/docs/5.0/cayenne-guide/maven_plugin" class="nav-link" id="maven_plugin">5.1. Maven Plugin</a></li>
<li><a href="/docs/5.0/cayenne-guide/gradle_plugin" class="nav-link" id="gradle_plugin">5.2. Gradle Plugin</a></li>
<li><a href="/docs/5.0/cayenne-guide/ant_tasks" class="nav-link" id="ant_tasks">5.3. Ant Tasks</a></li>
</ul></li>
<li><a href="/docs/5.0/cayenne-guide/appendix-a-configuration-properties" class="nav-link" id="appendix-a-configuration-properties">6. Appendix A. Configuration Properties</a></li>
<li><a href="/docs/5.0/cayenne-guide/appendix-b-service-collections" class="nav-link" id="appendix-b-service-collections">7. Appendix B. Service Collections</a></li>
</ul>
</div>
</div>
<div class="cd-toc-item">
</div>
</div>
</div>
<div class="col-12 col-lg-8 col-xl-9 py-3 pl-lg-5 cd-content">
<article>
<header>
</header>
<section>
<div class="sect2">
<h3 id="persistent-objects-objectcontext"><a class="anchor" href="#persistent-objects-objectcontext"></a>2.3. Persistent Objects and ObjectContext</h3>
<div class="sect3">
<h4 id="objectcontext"><a class="anchor" href="#objectcontext"></a>2.3.1. ObjectContext</h4>
<div class="paragraph">
<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 CayenneRuntime:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ObjectContext context = runtime.newContext();</code></pre>
</div>
</div>
<div class="paragraph">
<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>
</div>
<div class="paragraph">
<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 multiple 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 they decide to commit them or roll them back). Even for a single user it might make sense to use multiple ObjectContexts (e.g. request-scoped contexts to allow concurrent requests from the browser that change and commit objects independently).</p>
</div>
<div class="paragraph">
<p>ObjectContext is serializable and does not permanently hold 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>
<div class="sect3">
<h4 id="persistent-object-and-its-lifecycle"><a class="anchor" href="#persistent-object-and-its-lifecycle"></a>2.3.2. Persistent Object and its Lifecycle</h4>
<div class="paragraph">
<p>Cayenne can persist Java objects that implement the <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>
</div>
<div class="paragraph">
<p>The <code>Persistent</code> interface provides access to three persistence-related properties - <em>objectId</em>, <em>persistenceState</em> and <em>objectContext</em>. All three are initialized by the Cayenne runtime framework. Your application code should not attempt to change them. However, it is allowed to read them, which provides valuable runtime information. E.g. ObjectId can be used for a quick equality check of two objects, knowing persistence state would allow highlighting changed objects, etc.</p>
</div>
<div class="paragraph">
<p>Each persistent object belongs to a single ObjectContext, and can be in one of the following persistence states (as defined in <code>org.apache.cayenne.PersistenceState</code>) :</p>
</div>
<table id="persistenceStates" class="tableblock frame-all grid-all stretch table table-bordered">
<caption class="title">
Table 3. Persistence States
</caption>
<colgroup>
<col style="width: 20%;">
<col style="width: 80%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>TRANSIENT</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">The object is not registered with an ObjectContext and will not be persisted.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>NEW</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">The object is freshly registered in an ObjectContext, but has not been saved to the database yet and there is no matching database row.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>COMMITTED</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">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.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>MODIFIED</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">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.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>HOLLOW</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">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 COMMITTED.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle">
<p class="tableblock"><strong>DELETED</strong></p></td>
<td class="tableblock halign-left valign-top">
<p class="tableblock">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.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="objectcontext-persistence-api"><a class="anchor" href="#objectcontext-persistence-api"></a>2.3.3. ObjectContext Persistence API</h4>
<div class="paragraph">
<p>One of the first things users usually want to do with an <code>ObjectContext</code> is to select some objects from a database:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">List&lt;Artist&gt; artists = ObjectSelect.query(Artist.class)
.select(context);</code></pre>
</div>
</div>
<div class="paragraph">
<p>We’ll discuss queries in some detail in the <a href="/docs/5.0/cayenne-guide/queries">Queries</a> chapter. The example above is self-explanatory - we create a <code>ObjectSelect</code> that matches all <code>Artist</code> objects present in the database, and then use <code>select</code> to get the result.</p>
</div>
<div class="paragraph">
<p>Some queries can be quite complex, returning multiple result sets or even updating the database. For such queries, ObjectContext provides the <code>performGenericQuery()</code> method. While not commonly used, it is nevertheless important in some situations. E.g.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Collection&lt;Query&gt; queries = ... // multiple queries that need to be run together
QueryChain query = new QueryChain(queries);
QueryResponse response = context.performGenericQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>An application might modify selected objects. E.g.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist selectedArtist = artists.get(0);
selectedArtist.setName("Dali");</code></pre>
</div>
</div>
<div class="paragraph">
<p>The first time the object property is changed, the object’s state is automatically set to <strong>MODIFIED</strong> by Cayenne. Cayenne tracks all in-memory changes until a user calls <code>commitChanges</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">context.commitChanges();</code></pre>
</div>
</div>
<div class="paragraph">
<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, <code>commitChanges</code> commits just one object, but generally it can be any number of objects.</p>
</div>
<div class="paragraph">
<p>If, instead of commit, we wanted to reset all changed objects to the previously committed state, we’d call <code>rollbackChanges</code> instead:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">context.rollbackChanges();</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>newObject</code> method call creates a persistent object and sets its state to <strong>NEW</strong>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist newArtist = context.newObject(Artist.class);
newArtist.setName("Picasso");</code></pre>
</div>
</div>
<div class="paragraph">
<p>It only exists in memory until <code>commitChanges</code> 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 <code>INSERT</code> SQL statement to permanently store the object.</p>
</div>
<div class="paragraph">
<p>The <code>deleteObjects</code> method takes one or more <code>Persistent</code> objects and marks them as <strong>DELETED</strong>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">context.deleteObjects(artist1);
context.deleteObjects(artist2, artist3, artist4);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Additionally, <code>deleteObjects</code> 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 <code>commitChanges</code> is called. Similarly <code>rollbackChanges</code> will undo the effect of <code>newObject</code> and <code>deleteObjects</code>.</p>
</div>
<div class="paragraph">
<p><code>localObject</code> returns a copy of a given persistent object that is <em>local</em> to a given ObjectContext:</p>
</div>
<div class="paragraph">
<p>Since an application often works with more than one context, <code>localObject</code> 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>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ObjectContext editingContext = runtime.newContext();
Artist localArtist = editingContext.localObject(artist);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Often an application needs to inspect mapping metadata. This information is stored in the <code>EntityResolver</code> object, accessible via the <code>ObjectContext</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EntityResolver resolver = objectContext.getEntityResolver();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here we discussed the most commonly-used subset of the ObjectContext API. There are other useful methods, e.g. those allowing you to inspect registered objects' state in bulk, etc. Check the latest JavaDocs for details.</p>
</div>
</div>
<div class="sect3">
<h4 id="cayenne-helper-class"><a class="anchor" href="#cayenne-helper-class"></a>2.3.4. Cayenne Helper Class</h4>
<div class="paragraph">
<p>There is a useful helper class called <code>Cayenne</code> (fully-qualified name <code>org.apache.cayenne.Cayenne</code>) that builds on the 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>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">long pk = Cayenne.longPKForObject(artist);</code></pre>
</div>
</div>
<div class="paragraph">
<p>It also provides the reverse operation - finding an object given a known PK:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist artist = Cayenne.objectForPK(context, Artist.class, 34579);</code></pre>
</div>
</div>
<div class="paragraph">
<p>For more flexibility, you could use the <a href="/docs/5.0/cayenne-guide/queries#selectbyid">SelectById</a> query instead.</p>
</div>
<div class="paragraph">
<p>Feel free to explore the <code>Cayenne</code> class API for other useful methods.</p>
</div>
</div>
<div class="sect3">
<h4 id="objectcontext-nesting"><a class="anchor" href="#objectcontext-nesting"></a>2.3.5. ObjectContext Nesting</h4>
<div class="paragraph">
<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 a child is a nested context and selects or commits its objects via a parent.</p>
</div>
<div class="paragraph">
<p>Nesting is useful to create isolated object editing areas (child contexts) that all need to 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>
</div>
<div class="paragraph">
<p>In theory, Cayenne supports any number of nesting levels; however, applications should generally stay with one or two levels, as deep hierarchies will almost 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>
</div>
<div class="paragraph">
<p>To create a nested context, use an instance of CayenneRuntime, passing it the desired parent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ObjectContext parent = runtime.newContext();
ObjectContext nested = runtime.newContext(parent);</code></pre>
</div>
</div>
<div class="paragraph">
<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>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// merges nested context changes into the parent context
nested.commitChangesToParent();
// regular 'commitChanges' cascades commit through the chain
// of parent contexts all the way to the database
nested.commitChanges();</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// unrolls all local changes, getting context in a state identical to parent
nested.rollbackChangesLocally();
// regular 'rollbackChanges' cascades rollback through the chain of contexts
// all the way to the topmost parent
nested.rollbackChanges();</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="generic-persistent-objects"><a class="anchor" href="#generic-persistent-objects"></a>2.3.6. Generic Persistent Objects</h4>
<div class="paragraph">
<p>As described in the CayenneModeler chapter, Cayenne supports mapping of completely generic classes to specific entities. Although for convenience 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.</p>
</div>
<div class="paragraph">
<p>Generic objects are first-class citizens in Cayenne, and all common persistent operations apply to them as well. There are some peculiarities, however, described below.</p>
</div>
<div class="paragraph">
<p>When creating a generic object, either cast your ObjectContext to <code>DataContext</code> (that provides <code>newObject(String)</code> API), or provide your object with an explicit ObjectId:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Persistent generic = context.newObject("GenericEntity");</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Persistent generic = new GenericPersistentObject();
generic.setObjectId(ObjectId.of("GenericEntity"));
context.registerNewObject(generic);</code></pre>
</div>
</div>
<div class="paragraph">
<p>ObjectSelect for a generic object should be created by passing the entity name String, instead of just a Java class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ObjectSelect&lt;Persistent&gt; query = ObjectSelect.query(Persistent.class, "GenericEntity");</code></pre>
</div>
</div>
<div class="paragraph">
<p>Use Persistent API to access and modify properties of a generic object:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String name = (String) generic.readProperty("name");
generic.writeProperty("name", "New Name");</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is how an application can obtain the entity name of a generic object:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String entityName = generic.getObjectId().getEntityName();</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="transactions"><a class="anchor" href="#transactions"></a>2.3.7. Transactions</h4>
<div class="paragraph">
<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>
</div>
<div class="paragraph">
<p>Two cases where transactions need to be taken into consideration are container- and application-managed transactions.</p>
</div>
<div class="paragraph">
<p>If you are using Spring, EJB or another environment that manages transactions, you’ll likely need to switch the Cayenne runtime into "external transactions mode". This is done by setting the DI configuration property defined in <code>Constants.EXTERNAL_TX_PROPERTY</code> (see Appendix A). If this property is set to "true", 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 roll back the connections, leaving it up to the container to do that when appropriate.</p>
</div>
<div class="paragraph">
<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 via the <code>CayenneRuntime.performInTransaction</code> method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Integer result = runtime.performInTransaction(() -&gt; {
// commit one or more contexts
context1.commitChanges();
context2.commitChanges();
....
// after changing some objects in context1, commit again
context1.commitChanges();
....
// return an arbitrary result or null if we don't care about the result
return 5;
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>When inside a transaction, current thread Transaction object can be accessed via a static method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Transaction tx = BaseTransaction.getThreadTransaction();</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can control transaction isolation level and propagation logic using <code>TransactionDescriptor</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">TransactionDescriptor descriptor = TransactionDescriptor.builder()
.isolation(Connection.TRANSACTION_SERIALIZABLE)
.propagation(TransactionPropagation.REQUIRES_NEW)
.build();
runtime.performInTransaction(transactionalOperation, descriptor);</code></pre>
</div>
</div>
</div>
</div>
</section>
<footer>
<div class="row">
<div class="col-6 col-md-3 text-center text-md-left">
&nbsp;
</div>
<div class="col-18 col-md-9 text-center text-md-right">
<a class="btn btn-link" href='/docs/5.0/cayenne-guide/expressions/'>
<span class="d-block d-md-none text-muted">Next: </span>
Next: Cayenne Guide 5.0 · Expressions
<i class="small fa fa-chevron-right ml-3l2 d-none d-md-inline"></i>
</a>
</div>
</div>
</footer>
</article>
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=5c836e39-be6b-4a21-a946-a97b5b69f172" />
</div>
</div>
</div>
</main>
<footer class="bg-dark">
<div class="footer-nav container text-center text-lg-left pb-3">
<div class="row pt-5 pb-3">
<div class="col-sm-6 col-lg-3">
<h4>About</h4>
<ul class="list-unstyled">
<li>
<a href="/why-cayenne.html">Why Cayenne?</a>
</li>
<li>
<a href="/download/">Download</a>
</li>
<li>
<a href="/success-stories.html">Success Stories</a>
</li>
<li>
<a href="/about/support/">Support</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>Documentation</h4>
<ul class="list-unstyled">
<li>
<a href="/docs/4.0/getting-started-guide/">Getting Started (4.0)</a>
</li>
<li>
<a href="/docs/4.1/getting-started-guide/">Getting Started (4.1)</a>
</li>
<li>
<a href="/docs/4.2/getting-started-guide/">Getting Started (4.2)</a>
</li>
<li>
<a href="/docs/4.0/cayenne-guide/">Cayenne Guide (4.0)</a>
</li>
<li>
<a href="/docs/4.1/cayenne-guide/">Cayenne Guide (4.1)</a>
</li>
<li>
<a href="/docs/4.2/cayenne-guide/">Cayenne Guide (4.2)</a>
</li>
<li>
<a href="/docs/4.1/getting-started-db-first/">Database First tutorial (4.1)</a>
</li>
<li>
<a href="/docs/4.2/getting-started-db-first/">Database First tutorial (4.2)</a>
</li>
<li>
<a href="/legacy/legacy-docs/">Legacy Documentation</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>Collaboration</h4>
<ul class="list-unstyled">
<li>
<a href="https://issues.apache.org/jira/browse/CAY">Bug/Feature Tracker</a>
</li>
<li>
<a href="/mailing-lists.html">Mailing Lists</a>
</li>
<li>
<a href="/dev/code-repository.html">Code Repository</a>
</li>
<li>
<a href="/dev/">Developer Guide</a>
</li>
<li>
<a href="/how-can-i-help.html">How can I help?</a>
</li>
<li>
<a href="/contributors.html">Contributors</a>
</li>
<li>
<a href="/thanks.html">Thanks</a>
</li>
</ul>
</div>
<div class="col-sm-6 col-lg-3">
<h4>News</h4>
<ul class="list-multiline-items list-unstyled mb-0">
<li>
<time datetime="2023-05-25 18:00:00 &#43;0300 &#43;0300" class="xsmall d-block">May 25, 2023</time>
<a href="/2023/05/cayenne-42-final-released/">Cayenne 4.2 Final Released</a>
</li>
<li>
<time datetime="2023-03-02 12:00:00 &#43;0300 &#43;0300" class="xsmall d-block">Mar 02, 2023</time>
<a href="/2023/03/cayenne-403-released/">Cayenne 4.0.3 Released</a>
</li>
<li>
<time datetime="2022-12-05 12:00:00 &#43;0300 &#43;0300" class="xsmall d-block">Dec 05, 2022</time>
<a href="/2022/12/cayenne-42rc2-released/">Cayenne 4.2 Release Candidate 2 Released</a>
</li>
</ul>
<a class="btn-link text-uppercase xsmall" href="https://cayenne.apache.org/news">
More news
<i class="fa fa-lg fa-long-arrow-right" aria-hidden="true"></i>
</a>
</div>
</div>
<hr class="mt-0 mb-3" />
<p class="copy xsmall text-center mw-75 mx-auto mb-0">
Copyright © 2001-2024 Apache Software Foundation. Apache Cayenne, Cayenne, Apache, the Apache feather logo, and the Apache Cayenne project logo are trademarks of The Apache Software Foundation.
<a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a>.
<img class="d-block mx-auto mt-2" src="/img/logo_mono-3302daa3cf.svg" alt="Apache Cayenne" />
</p>
</div>
</footer>
</body>
</html>