blob: de2540e8ea4b81e9d93e449d7acf455613419932 [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 &middot; Apache Cayenne</title>
</head>
<body data-spy="scroll" data-target=".toc-side" 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 3.1
</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">
<a class="cd-toc-link" href="/docs/3.1/getting-started-guide/">Getting Started</a>
</div>
<div class="cd-toc-item">
<span class="cd-toc-link active">Cayenne Guide</span><div id="toc" class="toc toc-side">
<div id="toctitle">
Table of Contents
</div>
<ul class="sectlevel1 nav">
<li><a href="#object-relational-mapping-with-cayenne" class="nav-link">1. Object Relational Mapping with Cayenne</a>
<ul class="sectlevel2 nav">
<li><a href="#setup" class="nav-link">1.1. Setup</a></li>
<li><a href="#cayenne-mapping-structure" class="nav-link">1.2. Cayenne Mapping Structure</a></li>
<li><a href="#cayennemodeler-application" class="nav-link">1.3. CayenneModeler Application</a></li>
</ul> </li>
<li><a href="#cayenne-framework" class="nav-link">2. Cayenne Framework</a>
<ul class="sectlevel2 nav">
<li><a href="#include" class="nav-link">2.1. Including Cayenne in a Project</a></li>
<li><a href="#starting-cayenne" class="nav-link">2.2. Starting Cayenne</a></li>
<li><a href="#persistent-objects-and-objectcontext" class="nav-link">2.3. Persistent Objects and ObjectContext</a></li>
<li><a href="#expressions" class="nav-link">2.4. Expressions</a></li>
<li><a href="#orderings" class="nav-link">2.5. Orderings</a></li>
<li><a href="#queries" class="nav-link">2.6. Queries</a></li>
<li><a href="#lifecycle-events" class="nav-link">2.7. Lifecycle Events</a></li>
<li><a href="#performance-tuning" class="nav-link">2.8. Performance Tuning</a></li>
<li><a href="#customize" class="nav-link">2.9. Customizing Cayenne Runtime</a></li>
</ul> </li>
<li><a href="#cayenne-framework-remote-object-persistence" class="nav-link">3. Cayenne Framework - Remote Object Persistence</a>
<ul class="sectlevel2 nav">
<li><a href="#rop" class="nav-link">3.1. Introduction to ROP</a></li>
<li><a href="#implementing-rop-client" class="nav-link">3.2. Implementing ROP Client</a></li>
<li><a href="#implementing-rop-server" class="nav-link">3.3. Implementing ROP Server</a></li>
<li><a href="#implementing-rop-client-2" class="nav-link">3.4. Implementing ROP Client</a></li>
<li><a href="#rop-deployment" class="nav-link">3.5. ROP Deployment</a></li>
<li><a href="#current-limitations" class="nav-link">3.6. Current Limitations</a></li>
</ul> </li>
<li><a href="#appendix-a-configuration-properties" class="nav-link">4. Appendix A. Configuration Properties</a></li>
<li><a href="#appendix-b-service-collections" class="nav-link">5. Appendix B. Service Collections</a></li>
<li><a href="#appendix-c-expressions-bnf" class="nav-link">6. Appendix C. Expressions BNF</a></li>
<li><a href="#list-of-tables" class="nav-link">7. List of tables</a></li>
</ul>
</div>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/3.1/getting-started-rop/">Getting Started ROP</a>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/3.1/upgrade-guide/">Upgrade Guide</a>
</div>
<div class="cd-toc-item">
<a class="cd-toc-link" href="/docs/Apache_Cayenne_v3.1_javadoc.zip">Download JavaDoc</a></div>
</div>
</div>
<div class="col-12 col-lg-8 col-xl-9 py-3 pl-lg-5 cd-content">
<article>
<header>
<h1>Cayenne Guide</h1>
</header>
<section>
<div class="sect1">
<h2 id="object-relational-mapping-with-cayenne"><a class="anchor" href="#object-relational-mapping-with-cayenne"></a>1. Object Relational Mapping with Cayenne</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="setup"><a class="anchor" href="#setup"></a>1.1. Setup</h3>
<div class="sect3">
<h4 id="system-requirements"><a class="anchor" href="#system-requirements"></a>System Requirements</h4>
<div class="ulist">
<ul>
<li> <p>Java: Cayenne runtime framework and CayenneModeler GUI tool are written in 100% Java, and run on any Java-compatible platform. Required JDK version is 1.5 or higher. The last version of Cayenne compatible with JDK 1.4 is 1.2.x/2.0.x and JDK 1.3 is 1.1.x</p> </li>
<li> <p>JDBC Driver: An appropriate DB-specific JDBC driver is needed to access the database. It can be included in the application or used in web container DataSource configuration.</p> </li>
<li> <p>Third-party Libraries: Cayenne runtime framework has a minimal set of required and a few more optional dependencies on third-party open source packages. See "Including Cayenne in a Project" chapter for details.</p> </li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="runModeler"><a class="anchor" href="#runModeler"></a>Running CayenneModeler</h4>
<div class="paragraph">
<p>CayenneModeler GUI tool is intended to work with object relational mapping projects. While you can edit your XML by hand, it is rarely needed, as the Modeler is a pretty advanced tool included in Cayenne distribution. To obtain CayenneModeler, download Cayenne distribution archive from <a href="https://cayenne.apache.org/download/" class="bare">https://cayenne.apache.org/download/</a> matching the OS you are using. Of course Java needs to be installed on the machine where you are going to run the Modeler.</p>
</div>
<div class="ulist">
<ul>
<li> <p>OS X distribution contains CayenneModeler.app at the root of the distribution disk image.</p> </li>
<li> <p>Windows distribution contains CayenneModeler.exe file in the bin directory.</p> </li>
<li> <p>Cross-platform distribution (targeting Linux, but as the name implies, compatible with any OS) contains a runnable CayenneModeler.jar in the bin directory. It can be executed either by double-clicking, or if the environment is not configured to execute jars, by running from command-line:</p> </li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>$ java -jar CayenneModeler.jar</pre>
</div>
</div>
<div class="paragraph">
<p>The Modeler can also be started from Maven. While it may look like an exotic way to start a GUI application, it has its benefits - no need to download Cayenne distribution, the version of the Modeler always matches the version of the framework, the plugin can find mapping files in the project automatically. So it is an attractive option to some developers. Maven option requires a declaration in the POM:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml xml" data-lang="xml">&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.cayenne.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-cayenne-modeler-plugin&lt;/artifactId&gt;
&lt;version&gt;3.1.4-SNAPSHOT&lt;/version&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>And then can be run as</p>
</div>
<div class="listingblock">
<div class="content">
<pre>$ mvn cayenne-modeler:run</pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="cayenne-mapping-structure"><a class="anchor" href="#cayenne-mapping-structure"></a>1.2. Cayenne Mapping Structure</h3>
<div class="sect3">
<h4 id="cayenne-project"><a class="anchor" href="#cayenne-project"></a>Cayenne Project</h4>
<div class="paragraph">
<p>A Cayenne project is an XML representation of a model connecting database schema with Java classes. A project is normally created and manipulated via CayenneModeler GUI and then used to initialize Cayenne runtime. A project is made of one or more files. There’s always a root project descriptor file in any valid project. It is normally called <code>cayenne-xyz.xml</code>, where "xyz" is the name of the project.</p>
</div>
<div class="paragraph">
<p>Project descriptor can reference DataMap files, one per DataMap. DataMap files are normally called <code>xyz.map.xml</code>, where "xyz" is the name of the DataMap. For legacy reasons this naming convention is different from the convention for the root project descriptor above, and we may align it in the future versions. Here is how a typical project might look on the file system:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>~: ls -l
total 24
-rw-r--r-- 1 cayenne staff 491 Jan 28 18:25 cayenne-project.xml
-rw-r--r-- 1 cayenne staff 313 Jan 28 18:25 datamap.map.xml</pre>
</div>
</div>
<div class="paragraph">
<p>DataMap are referenced by name in the root descriptor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml xml" data-lang="xml">&lt;map name="datamap"/&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Map files are resolved by Cayenne by appending ".map.xml" extension to the map name, and resolving the resulting string relative to the root descriptor URI. The following sections discuss varios ORM model objects, without regards to their XML representation. XML format details are really unimportant to the Cayenne users.</p>
</div>
</div>
<div class="sect3">
<h4 id="datamap"><a class="anchor" href="#datamap"></a>DataMap</h4>
<div class="paragraph">
<p>DataMap is a container of persistent entities and other object-relational metadata. DataMap provides developers with a scope to organize their entities, but it does not provide a namespace for entities. In fact all DataMaps present in runtime are combined in a single namespace. Each DataMap must be associated with a DataNode. This is how Cayenne knows which database to use when running a query.</p>
</div>
</div>
<div class="sect3">
<h4 id="datanode"><a class="anchor" href="#datanode"></a>DataNode</h4>
<div class="paragraph">
<p>DataNode is model of a database. It is actually pretty simple. It has an arbitrary user-provided name and information needed to create or locate a JDBC DataSource. Most projects only have one DataNode, though there may be any number of nodes if needed.</p>
</div>
</div>
<div class="sect3">
<h4 id="dbentity"><a class="anchor" href="#dbentity"></a>DbEntity</h4>
<div class="paragraph">
<p>DbEntity is a model of a single DB table or view. DbEntity is made of DbAttributes that correspond to columns, and DbRelationships that map PK/FK pairs. DbRelationships are not strictly tied to FK constraints in DB, and should be mapped for all logical "relationships" between the tables.</p>
</div>
</div>
<div class="sect3">
<h4 id="objentity"><a class="anchor" href="#objentity"></a>ObjEntity</h4>
<div class="paragraph">
<p>ObjEntity is a model of a single persistent Java class. ObjEntity is made of ObjAttributes and ObjRelationships. Both correspond to entity class properties. However ObjAttributes represent "simple" properties (normally things like String, numbers, dates, etc.), while ObjRelationships correspond to properties that have a type of another entity.</p>
</div>
<div class="paragraph">
<p>ObjEntity maps to one or more DbEntities. There’s always one "root" DbEntity for each ObjEntity. ObjAttribiute maps to a DbAttribute or an Embeddable. Most often mapped DbAttribute is from the root DbEntity. Sometimes mapping is done to a DbAttribute from another DbEntity somehow related to the root DbEntity. Such ObjAttribute is called "flattened". Similarly ObjRelationship maps either to a single DbRelationship, or to a chain of DbRelationships ("flattened" ObjRelationship).</p>
</div>
<div class="paragraph">
<p>ObjEntities may also contain mapping of their lifecycle callback methods.</p>
</div>
</div>
<div class="sect3">
<h4 id="embeddable"><a class="anchor" href="#embeddable"></a>Embeddable</h4>
<div class="paragraph">
<p>Embeddable is a model of a Java class that acts as a single attribute of an ObjEntity, but maps to multiple columns in the database.</p>
</div>
</div>
<div class="sect3">
<h4 id="procedure"><a class="anchor" href="#procedure"></a>Procedure</h4>
<div class="paragraph">
<p>A model of a stored procedure in the database.</p>
</div>
</div>
<div class="sect3">
<h4 id="query"><a class="anchor" href="#query"></a>Query</h4>
<div class="paragraph">
<p>A model of a query. Cayenne allows queries to be mapped in Cayenne project, or created in the code. Depending on the circumstances the users may take one or the other approach.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="cayennemodeler-application"><a class="anchor" href="#cayennemodeler-application"></a>1.3. CayenneModeler Application</h3>
<div class="sect3">
<h4 id="working-with-mapping-projects"><a class="anchor" href="#working-with-mapping-projects"></a>Working with Mapping Projects</h4>
</div>
<div class="sect3">
<h4 id="reverse-engineering-database"><a class="anchor" href="#reverse-engineering-database"></a>Reverse Engineering Database</h4>
</div>
<div class="sect3">
<h4 id="generating-database-schema"><a class="anchor" href="#generating-database-schema"></a>Generating Database Schema</h4>
</div>
<div class="sect3">
<h4 id="migrations"><a class="anchor" href="#migrations"></a>Migrations</h4>
</div>
<div class="sect3">
<h4 id="generating-java-classes"><a class="anchor" href="#generating-java-classes"></a>Generating Java Classes</h4>
</div>
<div class="sect3">
<h4 id="modeling-inheritance"><a class="anchor" href="#modeling-inheritance"></a>Modeling Inheritance</h4>
</div>
<div class="sect3">
<h4 id="modeling-generic-persistent-classes"><a class="anchor" href="#modeling-generic-persistent-classes"></a>Modeling Generic Persistent Classes</h4>
<div class="paragraph">
<p>Normally each ObjEntity is mapped to a specific Java class (such as Artist or Painting) that explicitly declare all entity properties as pairs of getters and setters. However Cayenne allows to map a completly generic class to any number of entities. The only expectation is that a generic class implements org.apache.cayenne.DataObject. So an ideal candidate for a generic class is CayenneDataObject, or some custom subclass of CayenneDataObject.</p>
</div>
<div class="paragraph">
<p>If you don’t enter anything for Java Class of an ObjEntity, Cayenne assumes generic mapping and uses the following implicit rules to determine a class of a generic object. If DataMap "Custom Superclass" is set, runtime uses this class to instantiate new objects. If not, <code>org.apache.cayenne.CayenneDataObject</code> is used.</p>
</div>
<div class="paragraph">
<p>Class generation procedures (either done in the Modeler or with Ant or Maven) would skip entities that are mapped to CayenneDataObject explicitly or have no class mapping.</p>
</div>
</div>
<div class="sect3">
<h4 id="mapping-objattributes-to-custom-classes"><a class="anchor" href="#mapping-objattributes-to-custom-classes"></a>Mapping ObjAttributes to Custom Classes</h4>
</div>
<div class="sect3">
<h4 id="modeling-primary-key-generation-strategy"><a class="anchor" href="#modeling-primary-key-generation-strategy"></a>Modeling Primary Key Generation Strategy</h4>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cayenne-framework"><a class="anchor" href="#cayenne-framework"></a>2. Cayenne Framework</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="include"><a class="anchor" href="#include"></a>2.1. Including Cayenne in a Project</h3>
<div class="sect3">
<h4 id="jar-files-and-dependencies"><a class="anchor" href="#jar-files-and-dependencies"></a>Jar Files and Dependencies</h4>
<div class="paragraph">
<p>Cayenne distribution contains the following core runtime jars in the distribution lib directory:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>cayenne-server-x.x.jar</code> - contains full Cayenne runtime (DI, adapters, DB access classes, etc.). Most applications will use only this file.</p> </li>
<li> <p><code>cayenne-client-x.x.jar</code> - a subset of cayenne-server.jar trimmed for use on the client in an ROP application.</p> </li>
<li> <p>Other <code>cayenne-* jars</code> - various Cayenne extensions.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>When using <code>cayenne-server-x.x.jar</code> you’ll need a few third party jars (all included in <code>lib/third-party</code> directory of the distribution):</p>
</div>
<div class="ulist">
<ul>
<li> <p><a href="https://velocity.apache.org">Apache Velocity Template Engine</a>, version 1.6.x (and all its dependencies bundled with velocity-dep)</p> </li>
<li> <p><a href="https://commons.apache.org/proper/commons-collections/">Apache Commons Collections</a>, version 3.2.1</p> </li>
<li> <p><a href="https://commons.apache.org/proper/commons-logging/">Apache Commons Logging</a>, version 1.1</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Cayenne integrates with various caching, clustering and other frameworks. These optional integrations will require other third-party jars that the users will need to obtain on their own.</p>
</div>
</div>
<div class="sect3">
<h4 id="maven-projects"><a class="anchor" href="#maven-projects"></a>Maven Projects</h4>
<div class="paragraph">
<p>If you are using Maven, you won’t have to deal with figuring out the dependencies. You can simply include cayenne-server artifact in your POM:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml xml" data-lang="xml">&lt;dependency&gt;
&lt;groupId&gt;org.apache.cayenne&lt;/groupId&gt;
&lt;artifactId&gt;cayenne-server&lt;/artifactId&gt;
&lt;version&gt;3.1.4-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Additionally Cayenne provides a Maven plugin with a set of goals to perform various project tasks, such as synching generated Java classes with the mapping, described in the following subsection. The full plugin name is <code>org.apache.cayenne.plugins:cayenne-maven-plugin</code>.</p>
</div>
<div class="sect4">
<h5 id="cgen"><a class="anchor" href="#cgen"></a>cgen</h5>
<div class="paragraph">
<p><code>cgen</code> is a <code>cayenne-maven-plugin</code> goal that generates and maintains source (.java) files of persistent objects based on a DataMap. By default, it is bound to the generate-sources phase. If "makePairs" is set to "true" (which is the recommended default), this task will generate a pair of classes (superclass/subclass) for each ObjEntity in the DataMap. Superclasses should not be changed manually, since they are always overwritten. Subclasses are never overwritten and may be later customized by the user. If "makePairs" is set to "false", a single class will be generated for each ObjEntity.</p>
</div>
<div class="paragraph">
<p>By creating custom templates, you can use cgen to generate other output (such as web pages, reports, specialized code templates) based on DataMap information.</p>
</div>
<table id="tablecgen" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 1. cgen required parameters
</caption>
<colgroup>
<col style="width: 16.6666%;">
<col style="width: 16.6666%;">
<col style="width: 66.6668%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">map</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">File</p></td>
<td class="tableblock halign-left valign-top">
<div>
<div class="paragraph">
<p>DataMap XML file which serves as a source of metadata for class generation. E.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>${project.basedir}/src/main/resources/my.map.xml</code></pre>
</div>
</div>
</div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">destDir</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">File</p></td>
<td class="tableblock halign-left valign-top">
<div>
<div class="paragraph">
<p>Root destination directory for Java classes (ignoring their package names).</p>
</div>
</div></td>
</tr>
</tbody>
</table>
<table id="cgenOptional" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 2. cgen optional parameters
</caption>
<colgroup>
<col style="width: 22.2222%;">
<col style="width: 11.1111%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">additionalMaps</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">File</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A directory that contains additional DataMap XML files that may be needed to resolve cross-DataMap relationships for the the main DataMap, for which class generation occurs.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">client</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Whether we are generating classes for the client tier in a Remote Object Persistence application. "False" by default.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">embeddableTemplate</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Location of a custom Velocity template file for Embeddable class generation. If omitted, default template is used.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">embeddableSuperTemplate</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Location of a custom Velocity template file for Embeddable superclass generation. Ignored unless "makepairs" set to "true". If omitted, default template is used.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">encoding</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Generated files encoding if different from the default on current platform. Target encoding must be supported by the JVM running the build. Standard encodings supported by Java on all platforms are US-ASCII, ISO-8859-1, UTF-8, UTF-16BE, UTF-16LE, UTF-16. See javadocs for java.nio.charset.Charset for more information.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">excludeEntities</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A comma-separated list of ObjEntity patterns (expressed as a perl5 regex) to exclude from template generation. By default none of the DataMap entities are excluded.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">includeEntities</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A comma-separated list of ObjEntity patterns (expressed as a perl5 regex) to include from template generation. By default all DataMap entities are included.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">makePairs</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">If "true" (a recommended default), will generate subclass/superclass pairs, with all generated code placed in superclass.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">mode</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Specifies class generator iteration target. There are three possible values: "entity" (default), "datamap", "all". "entity" performs one generator iteration for each included ObjEntity, applying either standard to custom entity templates. "datamap" performs a single iteration, applying DataMap templates. "All" is a combination of entity and datamap.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">overwrite</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Only has effect when "makePairs" is set to "false". If "overwrite" is "true", will overwrite older versions of generated classes.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">superPkg</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Java package name of all generated superclasses. If omitted, each superclass will be placed in the subpackage of its subclass called "auto". Doesn’t have any effect if either "makepairs" or "usePkgPath" are false (both are true by default).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">superTemplate</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Location of a custom Velocity template file for ObjEntity superclass generation. Only has effect if "makepairs" set to "true". If omitted, default template is used.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">template</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Location of a custom Velocity template file for ObjEntity class generation. If omitted, default template is used.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">usePkgPath</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">If set to "true" (default), a directory tree will be generated in "destDir" corresponding to the class package structure, if set to "false", classes will be generated in "destDir" ignoring their package.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Example - a typical class generation scenario, where pairs of classes are generated with default Maven source destination and superclass package:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml xml" data-lang="xml">&lt;plugin&gt;
&lt;groupId&gt;org.apache.cayenne.plugins&lt;/groupId&gt;
&lt;artifactId&gt;cayenne-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;3.1.4-SNAPSHOT&lt;/version&gt;
&lt;!--
There's an intermittent problem when using Maven/cgen in Eclipse with m2eclipse plugin that
requires placing "configuration" section at the plugin level, instead of execution
level.
--&gt;
&lt;configuration&gt;
&lt;map&gt;${project.basedir}/src/main/resources/my.map.xml&lt;/map&gt;
&lt;destDir&gt;${project.basedir}/src/main/java&lt;/destDir&gt;
&lt;superPkg&gt;org.example.model.auto&lt;/superPkg&gt;
&lt;/configuration&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;goals&gt;
&lt;goal&gt;cgen&lt;/goal&gt;
&lt;/goals&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;/plugin&gt;</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="cdbgen"><a class="anchor" href="#cdbgen"></a>cdbgen</h5>
<div class="paragraph">
<p><code>cdbgen</code> is a <code>cayenne-maven-plugin</code> goal that drops and/or generates tables in a database on Cayenne DataMap. By default, it is bound to the pre-integration-test phase.</p>
</div>
<table id="cdbgenTable" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 3. cdbgen required parameters
</caption>
<colgroup>
<col style="width: 16.6666%;">
<col style="width: 16.6666%;">
<col style="width: 66.6668%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">map</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">File</p></td>
<td class="tableblock halign-left valign-top">
<div>
<div class="paragraph">
<p>DataMap XML file which serves as a source of metadata for class generation. E.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>${project.basedir}/src/main/resources/my.map.xml</code></pre>
</div>
</div>
</div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">driver</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A class of JDBC driver to use for the target database.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">url</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">JDBC connection URL of a target database.</p></td>
</tr>
</tbody>
</table>
<table id="cdbgenOptionl" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 4. cdbgen optional parameters
</caption>
<colgroup>
<col style="width: 16.6666%;">
<col style="width: 16.6666%;">
<col style="width: 66.6668%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">adapter</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Java class name implementing org.apache.cayenne.dba.DbAdapter. While this attribute is optional (a generic JdbcAdapter is used if not set), it is highly recommended to specify correct target adapter.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">createFK</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether cdbgen should create foreign key constraints. Default is "true".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">createPK</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether cdbgen should create Cayenne-specific auto PK objects. Default is "true".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">createTables</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether cdbgen should create new tables. Default is "true".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">dropPK</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether cdbgen should drop Cayenne primary key support objects. Default is "false".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">dropTables</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether cdbgen should drop the tables before attempting to create new ones. Default is "false".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">password</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Database user password.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">username</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Database user name.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Example - creating a DB schema on a local HSQLDB database:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml xml" data-lang="xml">&lt;plugin&gt;
&lt;groupId&gt;org.apache.cayenne.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-cayenne-plugin&lt;/artifactId&gt;
&lt;version&gt;3.1.4-SNAPSHOT&lt;/version&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;configuration&gt;
&lt;map&gt;${project.basedir}/src/main/resources/my.map.xml&lt;/map&gt;
&lt;url&gt;jdbc:hsqldb:hsql://localhost/testdb&lt;/url&gt;
&lt;adapter&gt;org.apache.cayenne.dba.hsqldb.HSQLDBAdapter&lt;/adapter&gt;
&lt;driver&gt;org.hsqldb.jdbcDriver&lt;/driver&gt;
&lt;username&gt;sa&lt;/username&gt;
&lt;/configuration&gt;
&lt;goals&gt;
&lt;goal&gt;cdbgen&lt;/goal&gt;
&lt;/goals&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;/plugin&gt;</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="mavenCdbimort"><a class="anchor" href="#mavenCdbimort"></a>cdbimport</h5>
<div class="paragraph">
<p><code>cdbimport</code> is a <code>maven-cayenne-plugin</code> goal that generates a DataMap based on an existing database schema. By default, it is bound to the generate-sources phase. This allows you to generate your DataMap prior to building your project, which may be necessary if you are also using the cgen task.</p>
</div>
<table id="cdbimportTable" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 5. cdbimport parameters
</caption>
<colgroup>
<col style="width: 20%;">
<col style="width: 10%;">
<col style="width: 20%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">map</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">File</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Yes</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">DataMap XML file which is the destination of the schema import. Can be an existing file. If this file does not exist, it is created when cdbimport is executed. E.g. <code>${project.basedir}/src/main/resources/my.map.xml</code>. If "overwrite" is true (the default), an existing DataMap will be used as a template for the new imported DataMap, i.e. all its entities will be cleared and recreated, but its common settings, such as default Java package, will be preserved (unless changed explicitly in the plugin configuration).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">driver</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Yes</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A class of JDBC driver to use for the target database.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">url</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Yes</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">JDBC connection URL of a target database.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">adapter</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">A Java class name implementing org.apache.cayenne.dba.DbAdapter. This attribute is optional. If not specified, AutoAdapter is used, which will attempt to guess the DB type.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">importProcedures</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether stored procedures should be imported from the database. Default is false.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">meaningfulPk</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether primary keys should be mapped as attributes of the ObjEntity. Default is false.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">namingStrategy</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">The naming strategy used for mapping database names to object entity names. Default is <code>org.apache.cayenne.map.naming.SmartNamingStrategy</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">overwriteExisting</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Indicates whether existing DB and object entities should be overwritten. This is an all-or-nothing setting. If you need finer granularity, use the CayenneModeler. Default is "true".</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">password</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Database user password.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">procedurePattern</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Pattern to match stored procedure names against for import. Default is to match all stored procedures. This value is only meaningful if importProcedures is true.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">schemaName</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Database schema to import tables/stored procedures from.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">tablePattern</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Pattern to match table names against for import. Default is to match all tables.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">username</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">String</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">No</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Database user name.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Example - loading a DB schema from a local HSQLDB database (essentially a reverse operation compared to the cdbgen example above) :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-XML XML" data-lang="XML">&lt;plugin&gt;
&lt;groupId&gt;org.apache.cayenne.plugins&lt;/groupId&gt;
&lt;artifactId&gt;cayenne-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;3.1.4-SNAPSHOT&lt;/version&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;configuration&gt;
&lt;map&gt;${project.basedir}/src/main/resources/my.map.xml&lt;/map&gt;
&lt;url&gt;jdbc:mysql://127.0.0.1/mydb&lt;/url&gt;
&lt;adapter&gt;org.apache.cayenne.dba.hsqldb.HSQLDBAdapter&lt;/adapter&gt;
&lt;driver&gt;com.mysql.jdbc.Driver&lt;/driver&gt;
&lt;username&gt;sa&lt;/username&gt;
&lt;/configuration&gt;
&lt;goals&gt;
&lt;goal&gt;cdbimport&lt;/goal&gt;
&lt;/goals&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;/plugin&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="ant-projects"><a class="anchor" href="#ant-projects"></a>Ant Projects</h4>
<div class="sect4">
<h5 id="cgen-2"><a class="anchor" href="#cgen-2"></a>cgen</h5>
</div>
<div class="sect4">
<h5 id="cdbgen-2"><a class="anchor" href="#cdbgen-2"></a>cdbgen</h5>
</div>
<div class="sect4">
<h5 id="cdbimport"><a class="anchor" href="#cdbimport"></a>cdbimport</h5>
<div class="paragraph">
<p>This is an Ant counterpart of "cdbimport" goal of cayenne-maven-plugin described above. It has exactly the same properties. Here is a usage example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-XML XML" data-lang="XML"> &lt;cdbimport map="${context.dir}/WEB-INF/my.map.xml"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1/mydb"
username="sa"/&gt;</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="cdataport"><a class="anchor" href="#cdataport"></a>cdataport</h5>
</div>
</div>
</div>
<div class="sect2">
<h3 id="starting-cayenne"><a class="anchor" href="#starting-cayenne"></a>2.2. Starting Cayenne</h3>
<div class="sect3">
<h4 id="starting-and-stopping-serverruntime"><a class="anchor" href="#starting-and-stopping-serverruntime"></a>Starting and Stopping ServerRuntime</h4>
<div class="paragraph">
<p>In runtime Cayenne is accessed via <code>org.apache.cayenne.configuration.server.ServerRuntime</code>. ServerRuntime is created by calling a convenient builder:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ServerRuntime runtime = new ServerRuntime("com/example/cayenne-project.xml");</code></pre>
</div>
</div>
<div class="paragraph">
<p>The parameter you pass to the builder is a location of the main project file. Location is a '/'-separated path (same path separator is used on UNIX and Windows) that is resolved relative to the application classpath. The project file can be placed in the root package or in a subpackage (e.g. in the code above it is in "com/example" subpackage).</p>
</div>
<div class="paragraph">
<p>ServerRuntime encapsulates a single Cayenne stack. Most applications will just have one ServerRuntime using it to create as many ObjectContexts as needed, access the Dependency Injection (DI) container and work with other Cayenne features. Internally ServerRuntime is just a thin wrapper around the DI container. Detailed features of the container are discussed in <a href="#customize">"Customizing Cayenne Runtime"</a> chapter. Here we’ll just show an example of how an application might turn on external transactions:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">public class MyExtensionsModule implements Module {
public void configure(Binder binder) {
binder.bind(QueryCache.class).to(EhCacheQueryCache.class);
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Module extensions = new MyExtensionsModule();
ServerRuntime runtime = new ServerRuntime("com/example/cayenne-project.xml", extensions);</code></pre>
</div>
</div>
<div class="paragraph">
<p>It is a good idea to shut down the runtime when it is no longer needed, usually before the application itself is shutdown:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">runtime.shutdown();</code></pre>
</div>
</div>
<div class="paragraph">
<p>When a runtime object has the same scope as the application, this may not be always necessary, however in some cases it is essential, and is generally considered a good practice. E.g. in a web container hot redeploy of a webapp will cause resource leaks and eventual OutOfMemoryError if the application fails to shutdown CayenneRuntime.</p>
</div>
</div>
<div class="sect3">
<h4 id="merging-multiple-projects"><a class="anchor" href="#merging-multiple-projects"></a>Merging Multiple Projects</h4>
<div class="paragraph">
<p>ServerRuntime requires at least one mapping project to run. But it can also take multiple projects and merge them together in a single configuration. This way different parts of a database can be mapped independenlty from each other (even by different software providers), and combined in runtime when assembling an application. Doing it is as easy as passing multiple project locations to ServerRuntime constructor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ServerRuntime runtime = new ServerRuntime(new String[] {
"com/example/cayenne-project.xml",
"org/foo/cayenne-library1.xml",
"org/foo/cayenne-library2.xml"
}
);</code></pre>
</div>
</div>
<div class="paragraph">
<p>When the projects are merged, the following rules are applied:</p>
</div>
<div class="ulist">
<ul>
<li> <p>The order of projects matters during merge. If there are two conflicting metadata objects belonging to two projects, an object from the last project takes precedence over the object from the first one. This makes possible to override pieces of metadata. This is also similar to how DI modules are merged in Cayenne.</p> </li>
<li> <p>Runtime DataDomain name is set to the name of the last project in the list.</p> </li>
<li> <p>Runtime DataDomain properties are the same as the properties of the last project in the list. I.e. properties are not merged to avoid invalid combinations and unexpected runtime behavior.</p> </li>
<li> <p>If there are two or more DataMaps with the same name, only one DataMap is used in the merged project, the rest are discarded. Same precedence rules apply - DataMap from the project with the highest index in the project list overrides all other DataMaps with the same name.</p> </li>
<li> <p>If there are two or more DataNodes with the same name, only one DataNode is used in the merged project, the rest are discarded. DataNode coming from project with the highest index in the project list is chosen per precedence rule above.</p> </li>
<li> <p>There is a notion of "default" DataNode. After the merge if any DataMaps are not explicitly linked to DataNodes, their queries will be executed via a default DataNode. This makes it possible to build mapping "libraries" that are only associated with a specific database in runtime. If there’s only one DataNode in the merged project, it will be automatically chosen as default. A possible way to explicitly designate a specific node as default is to override <code>DataDomainProvider.createAndInitDataDomain()</code>.</p> </li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="web-applications"><a class="anchor" href="#web-applications"></a>Web Applications</h4>
<div class="paragraph">
<p>Web applications can use a variety of mechanisms to configure and start the "services" they need, Cayenne being one of such services. Configuration can be done within standard Servlet specification objects like Servlets, Filters, or ServletContextListeners, or can use Spring, JEE CDI, etc. This is a user’s architectural choice and Cayenne is agnostic to it and will happily work in any environment. As described above, all that is needed is to create an instance of ServerRuntime somewhere and provide the application code with means to access it. And shut it down when the application ends to avoid container leaks.</p>
</div>
<div class="paragraph">
<p>Still Cayenne includes a piece of web app configuration code that can assist in quickly setting up simple Cayenne-enabled web applications. We are talking about CayenneFilter. It is declared in web.xml:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-XML XML" data-lang="XML">&lt;web-app&gt;
...
&lt;filter&gt;
&lt;filter-name&gt;cayenne-project&lt;/filter-name&gt;
&lt;filter-class&gt;org.apache.cayenne.configuration.web.CayenneFilter&lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;cayenne-project&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
...
&lt;/web-app&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>When started by the web container, it creates a instance of ServerRuntime and stores it in the ServletContext. Note that the name of Cayenne XML project file is derived from the "filter-name". In the example above CayenneFilter will look for an XML file "cayenne-project.xml". This can be overridden with "configuration-location" init parameter.</p>
</div>
<div class="paragraph">
<p>When the application runs, all HTTP requests matching the filter url-pattern will have access to a session-scoped ObjectContext like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java"> ObjectContext context = BaseContext.getThreadObjectContext();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Of course the ObjectContext scope, and other behavior of the Cayenne runtime can be customized via dependency injection. For this another filter init parameter called "extra-modules" is used. "extra-modules" is a comma or space-separated list of class names, with each class implementing Module interface. These optional custom modules are loaded after the the standard ones, which allows users to override all standard definitions.</p>
</div>
<div class="paragraph">
<p>For those interested in the DI container contents of the runtime created by CayenneFilter, it is the same ServerRuntime as would’ve been created by other means, but with an extra <code>org.apache.cayenne.configuration.web.WebModule</code> module that provides <code>org.apache.cayenne.configuration.web.RequestHandler</code> service. This is the service to override in the custom modules if you need to provide a different ObjectContext scope, etc.</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> You should not think of CayenneFilter as the only way to start and use Cayenne in a web application. In fact CayenneFilter is entirely optional. Use it if you don’t have any special design for application service management. If you do, simply integrate Cayenne into that design. </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="persistent-objects-and-objectcontext"><a class="anchor" href="#persistent-objects-and-objectcontext"></a>2.3. Persistent Objects and ObjectContext</h3>
<div class="sect3">
<h4 id="objectcontext"><a class="anchor" href="#objectcontext"></a>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 ServerRuntime:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ObjectContext context = runtime.getContext();</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 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>
</div>
<div class="paragraph">
<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>
<div class="sect3">
<h4 id="persistent-object-and-its-lifecycle"><a class="anchor" href="#persistent-object-and-its-lifecycle"></a>Persistent Object and its Lifecycle</h4>
<div class="paragraph">
<p>Cayenne can persist Java objects that implement <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>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. 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>
</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 spread table table-bordered">
<caption class="title">
Table 6. 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">TRANSIENT</p></td>
<td class="tableblock halign-left valign-middle"><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">NEW</p></td>
<td class="tableblock halign-left valign-middle"><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">COMMITED</p></td>
<td class="tableblock halign-left valign-middle"><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">MODIFIED</p></td>
<td class="tableblock halign-left valign-middle"><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">HOLLOW</p></td>
<td class="tableblock halign-left valign-middle"><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 COMMITED.</p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-middle"><p class="tableblock">DELETED</p></td>
<td class="tableblock halign-left valign-middle"><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>ObjectContext Persistence API</h4>
<div class="paragraph">
<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 "performQuery" method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class);
List&lt;Artist&gt; artists = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<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>
</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 "performGenericQuery"method. While not nearly as commonly-used as "performQuery", 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 "MODIFIED" by Cayenne. Cayenne tracks all in-memory changes until a user calls "commitChanges":</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 "commitChanges" 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>"newObject" method call creates a persistent object and sets its state to "NEW":</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 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>
</div>
<div class="paragraph">
<p><code>deleteObjects</code> method takes one or more Persistent objects and marks them as "DELETED":</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 "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>
</div>
<div class="paragraph">
<p><code>localObject</code> returns a copy of a given persistent object that is "local" to a given ObjectContext:</p>
</div>
<div class="paragraph">
<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>
</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 appliction needs to inspect mapping metadata. This information is stored in the EntityResolver object, accessible via the ObjectContext:</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 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>Cayenne Helper Class</h4>
<div class="paragraph">
<p>There is a useful helper class called "Cayenne" (fully-qualified name <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>
</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>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>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Artist artist = (Artist) Cayenne.objectForQuery(context, new SelectQuery(Artist.class));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Feel free to explore Cayenne class API for other useful methods.</p>
</div>
</div>
<div class="sect3">
<h4 id="objectcontext-nesting"><a class="anchor" href="#objectcontext-nesting"></a>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 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 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>
</div>
<div class="paragraph">
<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>
</div>
<div class="paragraph">
<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>
</div>
<div class="paragraph">
<p>To create a nested context, use an instance of ServerRuntime, 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.getContext();
ObjectContext nested = runtime.getContext((DataChannel) 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>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 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>
</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 pecularities however, described below.</p>
</div>
<div class="paragraph">
<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>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">DataObject generic = ((DataContext) context).newObject("GenericEntity");</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">DataObject generic = new CayenneDataObject();
generic.setObjectId(new ObjectId("GenericEntity"));
context.registerNewObject(generic);</code></pre>
</div>
</div>
<div class="paragraph">
<p>SelectQuery for generic object should be created passing entity name String in constructor, instead of a Java class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery("GenericEntity");</code></pre>
</div>
</div>
<div class="paragraph">
<p>Use DataObject 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 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>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-managed and application-managed transactions.</p>
</div>
<div class="paragraph">
<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 &gt; 'Container-Managed Transactions' checkbox), or in the code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">runtime.getDataDomain().setUsingExternalTransactions(true);</code></pre>
</div>
</div>
<div class="paragraph">
<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>
</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 with an explicit thread-bound transaction that surrounds a set of operations. Application is responsible for committing or rolling it back:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Transaction tx = runtime.getDataDomain().createTransaction();
Transaction.bindThreadTransaction(tx);
try {
// commit one or more contexts
context1.commitChanges();
context2.commitChanges();
....
// after changing some objects in context1, commit again
context1.commitChnages();
....
// if no failures, commit
tx.commit();
}
catch (Exception ex) {
tx.setRollbackOnly();
}
finally {
Transaction.bindThreadTransaction(null);
if (tx.getStatus() == Transaction.STATUS_MARKED_ROLLEDBACK) {
try {
tx.rollback();
}
catch (Exception rollbackEx) {
}
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="expressions"><a class="anchor" href="#expressions"></a>2.4. Expressions</h3>
<div class="sect3">
<h4 id="expressions-overview"><a class="anchor" href="#expressions-overview"></a>Expressions Overview</h4>
<div class="paragraph">
<p>Cayenne provides a simple yet powerful object-based expression language. The most common use of expressions are to build qualifiers and orderings of queries that are later converted to SQL by Cayenne and to evaluate in-memory against specific objects (to access certain values in the object graph or to perform in-memory object filtering and sorting). Cayenne provides API to build expressions in the code and a parser to create expressions from strings.</p>
</div>
</div>
<div class="sect3">
<h4 id="path-expressions"><a class="anchor" href="#path-expressions"></a>Path Expressions</h4>
<div class="paragraph">
<p>Before discussing how to build expressions, it is important to understand one group of expressions widely used in Cayenne - path expressions. There are two types of path expressions - object and database, used for navigating graphs of connected objects or joined DB tables respectively. Object paths are much more commonly used, as after all Cayenne is supposed to provide a degree of isolation of the object model from the database. However database paths are helpful in certain situations. General structure of path expressions is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre> [db:]segment[+][.segment[+]...]</pre>
</div>
</div>
<div class="ulist">
<ul>
<li> <p><code>db:</code> is an optional prefix indicating that the following path is a DB path. Otherwise it is an object path.</p> </li>
<li> <p><code>segment</code> is a name of a property (relationship or attribute in Cayenne terms) in the path. Path must have at least one segment; segments are separated by dot (".").</p> </li>
<li> <p><code>+</code> An "OUTER JOIN" path component. Currently "+" only has effect when translated to SQL as OUTER JOIN. When evaluating expressions in memory, it is ignored.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>An object path expression represents a chain of property names rooted in a certain (unspecified during expression creation) object and "navigating" to its related value. E.g. a path expression <code>artist.name</code> might be a property path starting from a Painting object, pointing to the related Artist object, and then to its name attribute. A few more examples:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>name</code> - can be used to navigate (read) the "name" property of a Person (or any other type of object that has a "name" property).</p> </li>
<li> <p><code>artist.exhibits.closingDate</code> - can be used to navigate to a closing date of any of the exhibits of a Painting’s Artist object.</p> </li>
<li> <p><code>artist.exhibits+.closingDate</code> - same as the previous example, but when translated into SQL, an OUTER JOIN will be used for "exhibits".</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Similarly a database path expression is a dot-separated path through DB table joins and columns. In Cayenne joins are mapped as DbRelationships with some symbolic names (the closest concept to DbRelationship name in the DB world is a named foreign key constraint. But DbRelationship names are usually chosen arbitrarily, without regard to constraints naming or even constraints presence). A database path therefore might look like this - <code>db:dbrelationshipX.dbrelationshipY.COLUMN_Z</code>. More specific examples:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>db:NAME</code> - can be used to navigate to the value of "NAME" column of some unspecified table.</p> </li>
<li> <p><code>db:artist.artistExhibits.exhibit.CLOSING_DATE</code> - can be used to match a closing date of any of the exhibits of a related artist record.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Cayenne supports "aliases" in path Expressions. E.g. the same expression can be written using explicit path or an alias:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>artist.exhibits.closingDate</code> - full path</p> </li>
<li> <p><code>e.closingDate</code> - alias <code>e</code> is used for <code>artist.exhibits</code>.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>SelectQuery using the second form of the path expression must be made aware of the alias via <code>SelectQuery.aliasPathSplits(..)</code>, otherwise an Exception will be thrown. The main use of aliases is to allow users to control how SQL joins are generated if the same path is encountered more than once in any given Expression. Each alias for any given path would result in a separate join. Without aliases, a single join will be used for a group of matching paths.</p>
</div>
</div>
<div class="sect3">
<h4 id="creating-expressions-from-strings"><a class="anchor" href="#creating-expressions-from-strings"></a>Creating Expressions from Strings</h4>
<div class="paragraph">
<p>While in most cases users are likely to rely on API from the following section for expression creation, we’ll start by showing String expressions, as this will help to understand the semantics. A Cayenne expression can be represented as a String, which can be converted to an expression object using <code>ExpressionFactory.exp</code> static method. Here is an example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String expString = "name like 'A%' and price &lt; 1000";
Expression exp = ExpressionFactory.exp(expString);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This particular expression may be used to match Paintings whose names that start with "A" and whose price is less than $1000. While this example is pretty self-explanatory, there are a few points worth mentioning. "name" and "price" here are object paths discussed earlier. As always, paths themselves are not attached to a specific root entity and can be applied to any entity that has similarly named attributes or relationships. So when we are saying that this expression "may be used to match Paintings", we are implying that there may be other entities, for which this expression is valid. Now the expression details…​</p>
</div>
<div class="paragraph">
<p>Character constants that are not paths or numeric values should be enclosed in single or double quotes. Two of the expressions below are equivalent:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">name = 'ABC'
// double quotes are escaped inside Java Strings of course
name = \"ABC\"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Case sensitivity. Expression operators are case sensitive and are usually lowercase. Complex words follow the Java camel-case style:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// valid
name likeIgnoreCase 'A%'
// invalid - will throw a parse exception
name LIKEIGNORECASE 'A%'</code></pre>
</div>
</div>
<div class="paragraph">
<p>Grouping with parenthesis:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">value = (price + 250.00) * 3</code></pre>
</div>
</div>
<div class="paragraph">
<p>Path prefixes. Object expressions are unquoted strings, optionally prefixed by <code>obj:</code> (usually they are not prefixed at all actually). Database expressions are always prefixed with <code>db:</code>. A special kind of prefix, not discussed yet is <code>enum:</code> that prefixes an enumeration constant:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// object path
name = 'Salvador Dali'
// same object path - a rarely used form
obj:name = 'Salvador Dali'
// multi-segment object path
artist.name = 'Salvador Dali'
// db path
db:NAME = 'Salvador Dali'
// enumeration constant
name = enum:org.foo.EnumClass.VALUE1</code></pre>
</div>
</div>
<div class="paragraph">
<p>Binary conditions are expressions that contain a path on the left, a value on the right, and some operation between them, such as equals, like, etc. They can be used as qualifiers in SelectQueries:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">name like 'A%'</code></pre>
</div>
</div>
<div class="paragraph">
<p>Named parameters. Expressions can have named parameters (names that start with "$"). Parameterized expressions allow to create reusable expression templates. Also if an Expression contains a complex object that doesn’t have a simple String representation (e.g. a Date, a DataObject, an ObjectId), parameterizing such expression is the only way to represent it as String. Here are some examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression template = Expression.fromString("name = $name");
...
Map p1 = Collections.singletonMap("name", "Salvador Dali");
Expression qualifier1 = template.expWithParameters(p1);
...
Map p2 = Collections.singletonMap("name", "Monet");
Expression qualifier2 = template.expWithParameters(p2);</code></pre>
</div>
</div>
<div class="paragraph">
<p>To create a named parameterized expression with a LIKE clause, SQL wildcards must be part of the values in the Map and not the expression string itself:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression template = Expression.fromString("name like $name");
...
Map p1 = Collections.singletonMap("name", "Salvador%");
Expression qualifier1 = template.expWithParameters(p1);</code></pre>
</div>
</div>
<div class="paragraph">
<p>When matching on a relationship, parameters can be Persistent objects or ObjectIds:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression template = Expression.fromString("artist = $artist");
...
Artist dali = // asume we fetched this one already
Map p1 = Collections.singletonMap("artist", dali);
Expression qualifier1 = template.expWithParameters(p1);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Uninitialized parameters will be automatically pruned from expressions, so a user can omit some parameters when creating an expression from a parameterized template:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression template = Expression.fromString("name like $name and dateOfBirth &gt; $date");
...
Map p1 = Collections.singletonMap("name", "Salvador%");
Expression qualifier1 = template.expWithParameters(p1);
// qualifier1 is now equals to "name like 'Salvador%'", the 'dateOfBirth' condition was
// pruned, as no value was specified for the $date parameter</code></pre>
</div>
</div>
<div class="paragraph">
<p>Null handling. Handling of Java nulls as operands is no different from normal values. Instead of using special conditional operators, like SQL does (IS NULL, IS NOT NULL), "=" and "!=" expressions are used directly with null values. It is up to Cayenne to translate expressions with nulls to the valid SQL.</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> A formal definition of all possible valid expressions in a form of JavaCC grammar is provided in Appendix C </td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect3">
<h4 id="creating-expressions-via-api"><a class="anchor" href="#creating-expressions-via-api"></a>Creating Expressions via API</h4>
<div class="paragraph">
<p>Creating expressions from Strings is a powerful and dynamic approach, however a safer alternative is to use Java API. It provides some degree of compile-time checking of expressions validity. The API is cenetred around ExpressionFactory class, and the Expression class. ExpressionFactory contains a number of rather self-explanatory factory methods. We won’t be going over all of them in detail, but will rather show a few general examples and some gotchas.</p>
</div>
<div class="paragraph">
<p>The following code recreates the expression from the previous chapter, but now using expression API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// String expression: name like 'A%' and price &lt; 1000
Expression e1 = ExpressionFactory.likeExp("name", "A%");
Expression e2 = ExpressionFactory.lessExp("price", 1000);
Expression finalExp = e1.andExp(e2);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is more verbose than creating it from String, but it is also more resilient to the entity properties renaming and precludes semantic errors in the expression String.</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> The last line in the example above shows how to create a new expression by "chaining" two other epxressions. A common error when chaining expressions is to assume that "andExp" and "orExp" append another expression to the current expression. In fact a new expression is created. I.e. Expression API treats existing expressions as immutable. </td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<p>As discussed earlier, Cayenne supports aliases in path Expressions, allowing to control how SQL joins are generated if the same path is encountered more than once in the same Expression. Two ExpressionFactory methods allow to implicitly generate aliases to "split" match paths into individual joins if needed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression matchAllExp(String path, Collection values)
Expression matchAllExp(String path, Object... values)</code></pre>
</div>
</div>
<div class="paragraph">
<p>"Path" argument to both of these methods can use a split character (a pipe symbol '|') instead of dot to indicate that relationship following a path should be split into a separate set of joins, one per collection value. There can only be one split at most in any given path. Split must always precede a relationship. E.g. <code>|exhibits.paintings</code>, <code>exhibits|paintings</code>, etc. Internally Cayenne would generate distinct aliases for each of the split expressions, forcing separate joins.</p>
</div>
</div>
<div class="sect3">
<h4 id="evaluete"><a class="anchor" href="#evaluete"></a>Evaluating Expressions in Memory</h4>
<div class="paragraph">
<p>When used in a query, an expression is converted to SQL WHERE clause (or ORDER BY clause) by Cayenne during query execution. Thus the actual evaluation against the data is done by the database engine. However the same expressions can also be used for accessing object properties, calculating values, in-memory filtering.</p>
</div>
<div class="paragraph">
<p>Checking whether an object satisfies an expression:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression e = ExpressionFactory.inExp("artistName", "John", "Bob");
Artist artist = ...
if(e.match(artist)) {
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Reading property value:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression e = Expression.fromString(User.NAME_PROPERTY);
String name = e.evaluate(user);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Filtering a list of objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Expression e = ExpressionFactory.inExp("artistName", "John", "Bob");
List&lt;Artist&gt; unfiltered = ...
List&lt;Artist&gt; filtered = e.filterObjects(unfiltered);</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> Current limitation of in-memory expressions is that no collections are permitted in the property path. </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="orderings"><a class="anchor" href="#orderings"></a>2.5. Orderings</h3>
<div class="paragraph">
<p>An Ordering object defines how a list of objects should be ordered. Orderings are essentially path expressions combined with a sorting strategy. Creating an Ordering:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Ordering o = new Ordering(Painting.NAME_PROPERTY, SortOrder.ASCENDING);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Like expressions, orderings are translated into SQL as parts of queries (and the sorting occurs in the database). Also like expressions, orderings can be used in memory, naturally - to sort objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">Ordering o = new Ordering(Painting.NAME_PROPERTY, SortOrder.ASCENDING_INSENSITIVE);
List&lt;Painting&gt; list = ...
o.orderList(list);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that unlike filtering with Expressions, ordering is performed in-place. This list object is reordered and no new list is created.</p>
</div>
</div>
<div class="sect2">
<h3 id="queries"><a class="anchor" href="#queries"></a>2.6. Queries</h3>
<div class="paragraph">
<p>Queries are Java objects used by the application to communicate with the database. Cayenne knows how to translate queries into SQL statements appropriate for a particular database engine. Most often queries are used to find objects matching certain criteria, but there are other types of queries too. E.g. those allowing to run native SQL, call DB stored procedures, etc. When committing objects, Cayenne itself creates special queries to insert/update/delete rows in the database.</p>
</div>
<div class="paragraph">
<p>There is a number of built-in queries in Cayenne, described later in this chapter. Most of the newer queries use fluent API and can be created and executed as easy-to-read one-liners. Users can define their own query types to abstract certain DB interactions that for whatever reason can not be adequately described by the built-in set.</p>
</div>
<div class="paragraph">
<p>Queries can be roughly categorized as "object" and "native". Object queries (most notably ObjectSelect, SelectById, and EJBQLQuery) are built with abstractions originating in the object model (the "object" side in the "object-relational" divide). E.g. ObjectSelect is assembled from a Java class of the objects to fetch, a qualifier expression, orderings, etc. - all of this expressed in terms of the object model.</p>
</div>
<div class="paragraph">
<p>Native queries describe a desired DB operation as SQL code (SQLSelect, SQLTemplate query) or a reference to a stored procedure (ProcedureQuery), etc. The results of native queries are usually presented as Lists of Maps, with each map representing a row in the DB (a term "data row" is often used to describe such a map). They can potentially be converted to objects, however it may take a considerable effort to do so. Native queries are also less (if at all) portable across databases than object queries.</p>
</div>
<div class="sect3">
<h4 id="select"><a class="anchor" href="#select"></a>SelectQuery</h4>
<div class="paragraph">
<p>SelectQuery is the most commonly used query in user applications. This may be the only query you will need in most appplications. It returns a list of persistent objects of a certain type specified in the query:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class);
List&lt;Artist&gt; objects = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This returned all rows in the "ARTIST" table. If the logs were turned on, you might see the following SQL printed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
INFO: === returned 5 row. - took 5 ms.</pre>
</div>
</div>
<div class="paragraph">
<p>This SQL was generated by Cayenne from the SelectQuery above. SelectQuery can have a qualifier to select only the data that you care about. Qualifier is simply an Expression (Expressions where discussed in the previous chapter). If you only want artists whose name begins with 'Pablo', you might use the following qualifier expression:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class,
ExpressionFactory.likeExp(Artist.NAME_PROPERTY, "Pablo%"));
List&lt;Artist&gt; objects = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The SQL will look different this time:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 WHERE t0.NAME LIKE ?
[bind: 1-&gt;NAME:'Pablo%']
INFO: === returned 1 row. - took 6 ms.</pre>
</div>
</div>
<div class="paragraph">
<p>SelectQuery allows to append parts of qualifier to self:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class);
query.setQualifier(ExpressionFactory.likeExp(Artist.NAME_PROPERTY, "A%"));
query.andQualifier(ExpressionFactory.greaterExp(Artist.DATE_OF_BIRTH_PROPERTY, someDate));</code></pre>
</div>
</div>
<div class="paragraph">
<p>To order the results of SelectQuery, one or more Orderings can be applied. Ordering were already discussed earlier. E.g.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class);
// create Ordering object explicitly
query.addOrdering(new Ordering(Artist.DATE_OF_BIRTH_PROPERTY, SortOrder.DESCENDING));
// or let SelectQuery create it behind the scenes
query.addOrdering(Artist.NAME_PROPERTY, SortOrder.ASCENDING);</code></pre>
</div>
</div>
<div class="paragraph">
<p>There’s a number of other useful properties in SelectQuery that define what to select and how to optimize database interaction (prefetching, caching, fetch offset and limit, pagination, etc.). Some of them are discussed in separate chapters on caching and performance optimization. Others are fairly self-explanatory. Please check the API docs for the full extent of the SelectQuery features.</p>
</div>
</div>
<div class="sect3">
<h4 id="ejbql"><a class="anchor" href="#ejbql"></a>EJBQLQuery</h4>
<div class="paragraph">
<p>EJBQLQuery was created as a part of an experiment in adopting some of Java Persistence API (JPA) approaches in Cayenne. It is a parameterized object query that is created from query String. A String used to build EJBQLQuery must conform to JPQL (JPA query language):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery query = new EJBQLQuery("select a FROM Artist a");</code></pre>
</div>
</div>
<div class="paragraph">
<p>JPQL details can be found in any JPA manual. Here we’ll mention only how this fits into Cayenne and what are the differences between EJBQL and other Cayenne queries.</p>
</div>
<div class="paragraph">
<p>Although most frequently EJBQLQuery is used as an alternative to SelectQuery, there are also DELETE and UPDATE varieties available.</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> As of this version of Cayenne, DELETE and UPDATE do not change the state of objects in the ObjectContext. They are run directly against the database instead. </td>
</tr>
</tbody>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery select = new EJBQLQuery("select a FROM Artist a WHERE a.name = 'Salvador Dali'");
List&lt;Artist&gt; artists = context.performQuery(select);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery delete = new EJBQLQuery("delete from Painting");
context.performGenericQuery(delete);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery update = new EJBQLQuery("UPDATE Painting AS p SET p.name = 'P2' WHERE p.name = 'P1'");
context.performGenericQuery(update);</code></pre>
</div>
</div>
<div class="paragraph">
<p>In most cases SelectQuery is preferred to EJBQLQuery, as it is API-based, and provides you with better compile-time checks. However sometimes you may want a completely scriptable object query. This is when you might prefer EJBQL. A more practical reason for picking EJBQL over SelectQuery though is that the former offers some extra selecting capabilities, namely aggregate functions and subqueries:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery query = new EJBQLQuery("select a, COUNT(p) FROM Artist a JOIN a.paintings p GROUP BY a");
List&lt;Object[]&gt; result = context.performQuery(query);
for(Object[] artistWithCount : result) {
Artist a = (Artist) artistWithCount[0];
int hasPaintings = (Integer) artistWithCount[1];
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This also demonstrates a previously unseen type of select result - a List of Object[] elements, where each entry in an Object[] is either a DataObject or a scalar, depending on the query SELECT clause. A result can also be a list of scalars:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">EJBQLQuery query = new EJBQLQuery("select a.name FROM Artist a");
List&lt;String&gt; names = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>While Cayenne Expressions discussed previously can be thought of as identical to JPQL WHERE clause, and indeed they are very close, there are a few noteable differences:</p>
</div>
<div class="ulist">
<ul>
<li> <p>Null handling: SelectQuery would translate the expressions matching NULL values to the corresponding "X IS NULL" or "X IS NOT NULL" SQL syntax. EJBQLQuery on the other hand requires explicit "IS NULL" (or "IS NOT NULL") syntax to be used, otherwise the generated SQL will look like "X = NULL" (or "X &lt;&gt; NULL"), which will evaluate differently.</p> </li>
<li> <p>Expression Parameters: SelectQuery uses "$" to denote named parameters (e.g. "$myParam"), while EJBQL uses ":" (e.g. ":myParam"). Also EJBQL supports positional parameters denoted by the question mark: "?3".</p> </li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="sqltemplate"><a class="anchor" href="#sqltemplate"></a>SQLTemplate</h4>
<div class="paragraph">
<p>SQLTemplate is a query that allows to run native SQL from a Cayenne application. It comes handy when the standard ORM concepts are not sufficient for a given query or an update. SQL is too powerful and allows to manipulate data in ways that are not easily described as a graph of related entities. Cayenne acknowledges this fact and provides this facility to execute SQL, mapping the result to objects when possible. Here are examples of selecting and non-selecting SQLTemplates:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SQLTemplate select = new SQLTemplate(Artist.class, "select * from ARTIST");
List&lt;Artist&gt; result = context.performQuery(select);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SQLTemplate update = new SQLTemplate(Artist.class, "delete from ARTIST");
QueryResponse response = context.performGenericQuery(update);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Cayenne doesn’t make any attempt to make sense of the SQL semantics, so it doesn’t know whether a given query is performing a select or update, etc. It is the the user’s decision to run a given query as a selecting or "generic".</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> Any data modifications done to DB as a result of SQLTemplate execution do not change the state of objects in the ObjectContext. So some objects in the context may become stale as a result. </td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<p>Another point to note is that the first argument to the SQLTemplate constructor - the Java class - has the same meaning as in SelectQuery only when the result can be converted to objects (e.g. when this is a selecting query and it is selecting all columns from one table). In this case it denotes the "root" entity of this query result. If the query does not denote a single entity result, this argument is only used for query routing, i.e. determining which database it should be run against. You are free to use any persistent class or even a DataMap instance in such situation. It will work as long as the passed "root" maps to the same database as the current query.</p>
</div>
<div class="paragraph">
<p>To achieve interoperability between mutliple RDBMS a user can specify multiple SQL statements for the same SQLTemplate, each corresponding to a native SQL dialect. A key used to look up the right dialect during execution is a fully qualified class name of the corresponding DbAdapter. If no DB-specific statement is present for a given DB, a default generic statement is used. E.g. in all the examples above a default statement will be used regardless of the runtime database. So in most cases you won’t need to explicitly "translate" your SQL to all possible dialects. Here is how this works in practice:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SQLTemplate select = new SQLTemplate(Artist.class, "select * from ARTIST");
// For Postgres it would be nice to trim padding of all CHAR columns.
// Otherwise those will be returned with whitespace on the right.
// assuming "NAME" is defined as CHAR...
String pgSQL = "SELECT ARTIST_ID, RTRIM(NAME), DATE_OF_BIRTH FROM ARTIST";
query.setTemplate(PostgresAdapter.class.getName(), pgSQL);</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="scripting-sqltemplate-with-velocity"><a class="anchor" href="#scripting-sqltemplate-with-velocity"></a>Scripting SQLTemplate with Velocity</h5>
<div class="paragraph">
<p>The most interesting aspect of SQLTemplate (and the reason why it is called a "template") is that a SQL string is treated by Cayenne as an Apache Velocity template. Before sending it to DB as a PreparedStatement, the String is evaluated in the Velocity context, that does variable substitutions, and performs special callbacks in response to various directives, thus controlling query interaction with the JDBC layer.</p>
</div>
<div class="paragraph">
<p>Check Velocity docs for the syntax details. Here we’ll just mention the two main scripting elements - "variables" (that look like <code>$var</code>) and "directives" (that look like <code>#directive(p1 p2 p3)</code>). All built-in Velocity directives are supported. Additionally Cayenne defines a number of its own directives to bind parameters to PreparedStatements and to control the structure of the ResultSet. These directives are described in the following sections.</p>
</div>
</div>
<div class="sect4">
<h5 id="variable-substitution"><a class="anchor" href="#variable-substitution"></a>Variable Substitution</h5>
<div class="paragraph">
<p>All variables in the template string are replaced from query parameters:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SQLTemplate query = new SQLTemplate(Artist.class, "delete from $tableName");
query.setParameters(Collections.singletonMap("tableName", "mydb.PAINTING"));
// this will generate SQL like this: "delete from mydb.PAINTING"</code></pre>
</div>
</div>
<div class="paragraph">
<p>The example above demonstrates the point made earlier in this chapter - even if we don’t know upfront which table the query will run against, we can still use a fixed "root" in constructor (<code>Artist.class</code> in this case) , as we are not planning on converting the result to objects.</p>
</div>
<div class="paragraph">
<p>Variable substitution within the text uses <code>"object.toString()"</code> method to replace the variable value. Keep in mind that this may not be appropriate in all situations. E.g. passing a date object in a WHERE clause expression may be converted to a String not understood by the target RDBMS SQL parser. In such cases variable should be wrapped in <code>#bind</code> directive as described below.</p>
</div>
</div>
<div class="sect4">
<h5 id="directives"><a class="anchor" href="#directives"></a>Directives</h5>
<div class="paragraph">
<p>These are the Cayenne directives used to customize SQLTemplate parsing and integrate it with the JDBC layer:</p>
</div>
<div class="sect5">
<h6 id="bind"><a class="anchor" href="#bind"></a>#bind</h6>
<div class="paragraph">
<p>Creates a PreparedStatement positional parameter in place of the directive, binding the value to it before statement execution. <code>#bind</code> is allowed in places where a "?" would be allowed in a PreparedStatement. And in such places it almost always makes sense to pass objects to the template via this or other forms of #bind instead of inserting them inline.</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bind(value)
#bind(value jdbcType)
#bind(value jdbcType scale)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>value</code> - can either be a char constant or a variable that is resolved from the query parameters. Note that the variable can be a collection, that will be automatically expanded into a list of individual value bindings. This is useful for instance to build IN conditions.</p> </li>
<li> <p><code>jdbcType</code> - is a JDBC data type of the parameter as defined in <code>java.sql.Types</code>.</p> </li>
<li> <p><code>scale</code> - An optional scale of the numeric value. Same as "scale" in PreparedStatement.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bind($xyz)
#bind('str')
#bind($xyz 'VARCHAR')
#bind($xyz 'DECIMAL' 2)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-SQL SQL" data-lang="SQL">update ARTIST set NAME = #bind($name) where ID = #bind($id)</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="bindequal"><a class="anchor" href="#bindequal"></a>#bindEqual</h6>
<div class="paragraph">
<p>Same as #bind, but also includes the "=" sign in front of the value binding. Look at the example below - we took the #bind example and replaced <code>"ID = #bind(..)"</code> with <code>"ID #bindEqual(..)"</code>. While it looks like a clumsy shortcut to eliminate the equal sign, the actual reason why this is useful is that it allows the value to be null. If the value is not null, <code>"= ?"</code> is generated, but if it is, the resulting chunk of the SQL would look like <code>"IS NULL"</code> and will be compilant with what the DB expects.</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindEqual(value)
#bindEqual(value jdbcType)
#bindEqual(value jdbcType scale)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments: (same as #bind)</p>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindEqual($xyz)
#bindEqual('str')
#bindEqual($xyz 'VARCHAR')
#bindEqual($xyz 'DECIMAL' 2)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-SQL SQL" data-lang="SQL">update ARTIST set NAME = #bind($name) where ID #bindEqual($id)</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="bindnotequal"><a class="anchor" href="#bindnotequal"></a>#bindNotEqual</h6>
<div class="paragraph">
<p>This directive deals with the same issue as <code>#bindEqual</code> above, only it generates "not equal" in front of the value (or IS NOT NULL).</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindNotEqual(value)
#bindNotEqual(value jdbcType)
#bindNotEqual(value jdbcType scale)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments: (same as #bind)</p>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindNotEqual($xyz)
#bindNotEqual('str')
#bindNotEqual($xyz 'VARCHAR')
#bindNotEqual($xyz 'DECIMAL' 2)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-SQL SQL" data-lang="SQL">update ARTIST set NAME = #bind($name) where ID #bindEqual($id)</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="bindobjectequal"><a class="anchor" href="#bindobjectequal"></a>#bindObjectEqual</h6>
<div class="paragraph">
<p>It can be tricky to use a Persistent object or an ObjectId in a binding, especially for tables with compound primary keys. This directive helps to handle such binding. It maps columns in the query to the names of Persistent object ID columns, extracts ID values from the object, and generates SQL like "COL1 = ? AND COL2 = ? …​" , binding positional parameters to ID values. It can also correctly handle null object. Also notice how we are specifying a Velocity array for multi-column PK.</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindObjectEqual(value columns idColumns)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>value</code> - must be a variable that is resolved from the query parameters to a Persistent or ObjectId.</p> </li>
<li> <p><code>columns</code> - the names of the columns to generate in the SQL.</p> </li>
<li> <p><code>idColumn</code> - the names of the ID columns for a given entity. Must match the order of "columns" to match against.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindObjectEqual($a 't0.ID' 'ID')
#bindObjectEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String sql = "SELECT * FROM PAINTING t0 WHERE #bindObjectEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) ORDER BY PAINTING_ID";
SQLTemplate select = new SQLTemplate(Artist.class, sql);
Artist a = ....
select.setParameters(Collections.singletonMap("a", a));</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="bindobjectnotequal"><a class="anchor" href="#bindobjectnotequal"></a>#bindObjectNotEqual</h6>
<div class="paragraph">
<p>Same as #bindObjectEqual above, only generates "not equal" operator for value comparison (or IS NOT NULL).</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindObjectNotEqual(value columns idColumns)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments: (same as #bindObjectEqual)</p>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#bindObjectNotEqual($a 't0.ID' 'ID')
#bindObjectNotEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String sql = "SELECT * FROM PAINTING t0 WHERE #bindObjectNotEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) ORDER BY PAINTING_ID";
SQLTemplate select = new SQLTemplate(Artist.class, sql);
Artist a = ....
select.setParameters(Collections.singletonMap("a", a));</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="result"><a class="anchor" href="#result"></a>#result</h6>
<div class="paragraph">
<p>Renders a column in SELECT clause of a query and maps it to a key in the result DataRow. Also ensures the value read is of the correct type. This allows to create a DataRow (and ultimately - a persistent object) from an arbitrary ResultSet.</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#result(column)
#result(column javaType)
#result(column javaType alias)
#result(column javaType alias dataRowKey)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Arguments:</p>
</div>
<div class="ulist">
<ul>
<li> <p><code>column</code> - the name of the column to render in SQL SELECT clause.</p> </li>
<li> <p><code>javaType</code> - a fully-qualified Java class name for a given result column. For simplicity most common Java types used in JDBC can be specified without a package. These include all numeric types, primitives, String, SQL dates, BigDecimal and BigInteger. So <code>"#result('A' 'String')"</code>, <code>"#result('B' 'java.lang.String')"</code> and <code>"#result('C' 'int')"</code> are all valid</p> </li>
<li> <p><code>alias</code> - specifies both the SQL alias of the column and the value key in the DataRow. If omitted, "column" value is used.</p> </li>
<li> <p><code>dataRowKey</code> - needed if SQL 'alias' is not appropriate as a DataRow key on the Cayenne side. One common case when this happens is when a DataRow retrieved from a query is mapped using joint prefetch keys (see below). In this case DataRow must use database path expressions for joint column keys, and their format is incompatible with most databases alias format.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>Usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#result('NAME')
#result('DATE_OF_BIRTH' 'java.util.Date')
#result('DOB' 'java.util.Date' 'DATE_OF_BIRTH')
#result('DOB' 'java.util.Date' '' 'artist.DATE_OF_BIRTH')
#result('SALARY' 'float')</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-SQL SQL" data-lang="SQL">SELECT #result('ID' 'int'), #result('NAME' 'String'), #result('DATE_OF_BIRTH' 'java.util.Date') FROM ARTIST</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="chain-and-chunk"><a class="anchor" href="#chain-and-chunk"></a>#chain and #chunk</h6>
<div class="paragraph">
<p><code>#chain</code> and <code>#chunk</code> directives are used for conditional inclusion of SQL code. They are used together with <code>#chain</code> wrapping multiple <code>#chunks</code>. A chunk evaluates its parameter expression and if it is NULL suppresses rendering of the enclosed SQL block. A chain renders its prefix and its chunks joined by the operator. If all the chunks are suppressed, the chain itself is suppressed. This allows to work with otherwise hard to script SQL semantics. E.g. a WHERE clause can contain multiple conditions joined with AND or OR. Application code would like to exclude a condition if its right-hand parameter is not present (similar to Expression pruning discussed above). If all conditions are excluded, the entire WHERE clause should be excluded. chain/chunk allows to do that.</p>
</div>
<div class="paragraph">
<p>Semantics:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#chain(operator) ... #end
#chain(operator prefix) ... #end
#chunk() ... #end
#chunk(param) ... #end</code></pre>
</div>
</div>
<div class="paragraph">
<p>Full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>#chain('OR' 'WHERE')
#chunk($name) NAME LIKE #bind($name) #end"
#chunk($id) ARTIST_ID &gt; #bind($id) #end"
#end"</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="mapping-sqltemplate-results"><a class="anchor" href="#mapping-sqltemplate-results"></a>Mapping SQLTemplate Results</h6>
<div class="paragraph">
<p>Here we’ll discuss how to convert the data selected via SQLTemplate to some useable format, compatible with other query results. It can either be very simple or very complex, depending on the structure of the SQL, JDBC driver nature and the desired result structure. This section presents various tips and tricks dealing with result mapping.</p>
</div>
<div class="paragraph">
<p>By default SQLTemplate is expected to return a List of Persistent objects of its root type. This is the simple case:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
// List of Artists
List&lt;Artist&gt; artists = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Just like SelectQuery, SQLTemplate can fetch DataRows. In fact DataRows option is very useful with SQLTemplate, as the result type most often than not does not represent a Cayenne entity, but instead may be some aggregated report or any other data whose object structure is opaque to Cayenne:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">String sql = "SELECT t0.NAME, COUNT(1) FROM ARTIST t0 JOIN PAINTING t1 ON (t0.ID = t1.ARTIST_ID) "
+ "GROUP BY t0.NAME ORDER BY COUNT(1)";
SQLTemplate query = new SQLTemplate(Artist.class, sql);
// ensure we are fetching DataRows
query.setFetchingDataRows(true);
// List of DataRow
List&lt;DataRow&gt; rows = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the example above, even though the query root is Artist. the result is a list of artist names with painting counts (as mentioned before in such case "root" is only used to find the DB to fetch against, but has no bearning on the result). The DataRows here are the most appropriate and desired result type.</p>
</div>
<div class="paragraph">
<p>In a more advanced case you may decide to fetch a list of scalars or a list of Object[] with each array entry being either an entity or a scalar. You probably won’t be doing this too often and it requires quite a lot of work to setup, but if you want your SQLTemplate to return results similar to EJBQLQuery, it is doable using SQLResult as described below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate(Painting.class, "SELECT ESTIMATED_PRICE P FROM PAINTING");
// let Cayenne know that result is a scalar
SQLResult resultDescriptor = new SQLResult();
resultDescriptor.addColumnResult("P");
query.setResult(resultDescriptor);
// List of BigDecimals
List&lt;BigDecimal&gt; prices = context.performQuery(query);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate(Artist.class, "SELECT t0.ID, t0.NAME, t0.DATE_OF_BIRTH, COUNT(t1.PAINTING_ID) C " +
"FROM ARTIST t0 LEFT JOIN PAINTING t1 ON (t0.ID = t1.ARTIST_ID) " +
"GROUP BY t0.ID, t0.NAME, t0.DATE_OF_BIRTH");
// let Cayenne know that result is a mix of Artist objects and the count of their paintings
EntityResult artistResult = new EntityResult(Artist.class);
artistResult.addDbField(Artist.ID_PK_COLUMN, "ARTIST_ID");
artistResult.addObjectField(Artist.NAME_PROPERTY, "NAME");
artistResult.addObjectField(Artist.DATE_OF_BIRTH_PROPERTY, "DATE_OF_BIRTH");
SQLResult resultDescriptor = new SQLResult();
resultDescriptor.addEntityResult(artistResult);
resultDescriptor.addColumnResult("C");
query.setResult(resultDescriptor);
// List of Object[]
List&lt;Object[]&gt; data = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Another trick related to mapping result sets is making Cayenne recognize prefetched entities in the result set. This emulates "joint" prefetching of SelectQuery, and is achieved by special column naming. Columns belonging to the "root" entity of the query should use unqualified names corresponding to the root DbEntity columns. For each related entity column names must be prefixed with relationship name and a dot (e.g. "toArtist.ID"). Column naming can be controlled with "#result" directive:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">String sql = "SELECT distinct "
+ "#result('t1.ESTIMATED_PRICE' 'BigDecimal' '' 'paintings.ESTIMATED_PRICE'), "
+ "#result('t1.PAINTING_TITLE' 'String' '' 'paintings.PAINTING_TITLE'), "
+ "#result('t1.GALLERY_ID' 'int' '' 'paintings.GALLERY_ID'), "
+ "#result('t1.ID' 'int' '' 'paintings.ID'), "
+ "#result('NAME' 'String'), "
+ "#result('DATE_OF_BIRTH' 'java.util.Date'), "
+ "#result('t0.ID' 'int' '' 'ID') "
+ "FROM ARTIST t0, PAINTING t1 "
+ "WHERE t0.ID = t1.ARTIST_ID";
SQLTemplate q = new SQLTemplate(Artist.class, sql);
q.addPrefetch(Artist.PAINTINGS_PROPERTY)
List&lt;Artist&gt; objects = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>And the final tip deals with capitalization of the DataRow keys. Queries like <code>"SELECT * FROM…​"</code> and even <code>"SELECT COLUMN1, COLUMN2, …​ FROM …​"</code> can sometimes result in Cayenne exceptions on attempts to convert fetched DataRows to objects. Essentially any query that is not using a <code>#result</code> directive to describe the result set is prone to this problem, as different databases may produce different capitalization of the java.sql.ResultSet columns.</p>
</div>
<div class="paragraph">
<p>The most universal way to address this issue is to describe each column explicitly in the SQLTemplate via <code>#result</code>, e.g.: <code>"SELECT #result('column1'), #result('column2'), .."</code>. However this quickly becomes impractical for tables with lots of columns. For such cases Cayenne provides a shortcut based on the fact that an ORM mapping usually follows some naming convention for the column names. Simply put, for case-insensitive databases developers normally use either all lowercase or all uppercase column names. Here is the API that takes advantage of that user knowledge and forces Cayenne to follow a given naming convention for the DataRow keys (this is also available as a dropdown in the Modeler):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
query.setColumnNamesCapitalization(CapsStrategy.LOWER);
List objects = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>or</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
query.setColumnNamesCapitalization(CapsStrategy.UPPER);
List objects = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>None of this affects the generated SQL, but the resulting DataRows are using correct capitalization. Note that you probably shouldn’t bother with this unless you are getting CayenneRuntimeExceptions when fetching with SQLTemplate.</p>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="procedurequery"><a class="anchor" href="#procedurequery"></a>ProcedureQuery</h4>
<div class="paragraph">
<p>Stored procedures are mapped as separate objects in CayenneModeler. ProcedureQuery provides a way to execute them with a certain set of parameters. Just like with SQLTemplate, the outcome of a procedure can be anything - a single result set, mutliple result sets, some data modification (returned as an update count), or a combination of these. So use "performQuery" to get a single result set, and use "performGenericQuery" for anything else:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ProcedureQuery query = new ProcedureQuery("my_procedure", Artist.class);
// Set "IN" parameter values
query.addParam("p1", "abc");
query.addParam("p2", 3000);
List&lt;Artist&gt; result = context.performQuery(query);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">// here we do not bother with root class.
// Procedure name gives us needed routing information
ProcedureQuery query = new ProcedureQuery("my_procedure");
query.addParam("p1", "abc");
query.addParam("p2", 3000);
QueryResponse response = context.performGenericQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>A stored procedure can return data back to the application as result sets or via OUT parameters. To simplify the processing of the query output, QueryResponse treats OUT parameters as if it was a separate result set. If a stored procedure declares any OUT or INOUT parameters, QueryResponse will contain their returned values in the very first result list:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">ProcedureQuery query = new ProcedureQuery("my_procedure");
QueryResponse response = context.performGenericQuery(query);
// read OUT parameters
List out = response.firstList();
if(!out.isEmpty()) {
Map outParameterValues = (Map) outList.get(0);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>There maybe a situation when a stored procedure handles its own transactions, but an application is configured to use Cayenne-managed transactions. This is obviously conflicting and undesirable behavior. In this case ProcedureQueries should be executed explicitly wrapped in an "external" Transaction. This is one of the few cases when a user should worry about transactions at all. See Transactions section for more details.</p>
</div>
</div>
<div class="sect3">
<h4 id="namedquery"><a class="anchor" href="#namedquery"></a>NamedQuery</h4>
<div class="paragraph">
<p>NamedQuery is a query that is a reference to another query stored in the DataMap. The actual stored query can be SelectQuery, SQLTemplate, EJBQLQuery, etc. It doesn’t matter - the API for calling them is the same - via a NamedQuery:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">String[] keys = new String[] {"loginid", "password"};
Object[] values = new String[] {"joe", "secret"};
NamedQuery query = new NamedQuery("Login", keys, values);
List&lt;User&gt; matchingUsers = context.performQuery(query);</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="custom-queries"><a class="anchor" href="#custom-queries"></a>Custom Queries</h4>
<div class="paragraph">
<p>If a user needs some extra functionality not addressed by the existing set of Cayenne queries, he can write his own. The only requirement is to implement <code>org.apache.cayenne.query.Query</code> interface. The easiest way to go about it is to subclass some of the base queries in Cayenne.</p>
</div>
<div class="paragraph">
<p>E.g. to do something directly in the JDBC layer, you might subclass AbstractQuery:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">public class MyQuery extends AbstractQuery {
@Override
public SQLAction createSQLAction(SQLActionVisitor visitor) {
return new SQLAction() {
@Override
public void performAction(Connection connection, OperationObserver observer) throws SQLException, Exception {
// 1. do some JDBC work using provided connection...
// 2. push results back to Cayenne via OperationObserver
}
};
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>To delegate the actual query execution to a standard Cayenne query, you may subclass IndirectQuery:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">public class MyDelegatingQuery extends IndirectQuery {
@Override
protected Query createReplacementQuery(EntityResolver resolver) {
SQLTemplate delegate = new SQLTemplate(SomeClass.class, generateRawSQL());
delegate.setFetchingDataRows(true);
return delegate;
}
protected String generateRawSQL() {
// build some SQL string
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In fact many internal Cayenne queries are IndirectQueries, delegating to SelectQuery or SQLTemplate after some preprocessing.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="lifecycle-events"><a class="anchor" href="#lifecycle-events"></a>2.7. Lifecycle Events</h3>
<div class="paragraph">
<p>An application might be interested in getting notified when a Persistent object moves through its lifecycle (i.e. fetched from DB, created, modified, committed). E.g. when a new object is created, the application may want to initialize its default properties (this can’t be done in constructor, as constructor is also called when an object is fetched from DB). Before save, the application may perform validation and/or set some properties (e.g. "updatedTimestamp"). After save it may want to create an audit record for each saved object, etc., etc.</p>
</div>
<div class="paragraph">
<p>All this can be achieved by declaring callback methods either in Persistent objects or in non-persistent listener classes defined by the application (further simply called "listeners"). There are eight types of lifecycle events supported by Cayenne, listed later in this chapter. When any such event occurs (e.g. an object is committed), Cayenne would invoke all appropriate callbacks. Persistent objects would receive their own events, while listeners would receive events from any objects.</p>
</div>
<div class="paragraph">
<p>Cayenne allows to build rather powerful and complex "workflows" or "processors" tied to objects lifecycle, especially with listeners, as they have full access to the application evnironment outside Cayenne. This power comes from such features as filtering which entity events are sent to a given listener and the ability to create a common operation context for multiple callback invocations. All of these are discussed later in this chapter.</p>
</div>
<div class="sect3">
<h4 id="types-of-lifecycle-events"><a class="anchor" href="#types-of-lifecycle-events"></a>Types of Lifecycle Events</h4>
<div class="paragraph">
<p>Cayenne defines the following 8 types of lifecycle events for which callbacks can be regsitered:</p>
</div>
<table id="lifecycleEvent" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 7. Lifecycle Event Types
</caption>
<colgroup>
<col style="width: 20%;">
<col style="width: 80%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Event</th>
<th class="tableblock halign-left valign-top">Occurs…​</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PostAdd</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right after a new object is created inside <code>ObjectContext.newObject()</code>. When this event is fired the object is already registered with its ObjectContext and has its ObjectId and ObjectContext properties set.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PrePersist</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right before a new object is committed, inside <code>ObjectContext.commitChanges()</code> and <code>ObjectContext.commitChangesToParent()</code> (and after <code>"validateForInsert()"</code>).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PreUpdate</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right before a modified object is committed, inside <code>ObjectContext.commitChanges()</code> and <code>ObjectContext.commitChangesToParent()</code> (and after <code>"validateForUpdate()"</code>).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PreRemove</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right before an object is deleted, inside <code>ObjectContext.deleteObjects()</code>. The event is also generated for each object indirectly deleted as a result of CASCADE delete rule.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PostPersist</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right after a commit of a new object is done, inside <code>ObjectContext.commitChanges()</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PostUpdate</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right after a commit of a modified object is done, inside <code>ObjectContext.commitChanges()</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PostRemove</p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">right after a commit of a deleted object is done, inside <code>ObjectContext.commitChanges()</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock">PostLoad</p></td>
<td class="tableblock halign-left valign-top">
<div>
<div class="ulist">
<ul>
<li> <p>After an object is fetched inside ObjectContext.performQuery().</p> </li>
<li> <p>After an object is reverted inside ObjectContext.rollbackChanges().</p> </li>
<li> <p>Anytime a faulted object is resolved (i.e. if a relationship is fetched).</p> </li>
</ul>
</div>
</div></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="callbacks-on-persistent-objects"><a class="anchor" href="#callbacks-on-persistent-objects"></a>Callbacks on Persistent Objects</h4>
<div class="paragraph">
<p>Callback methods on Persistent classes are mapped in CayenneModeler for each ObjEntity. Empty callback methods are automatically created as a part of class generation (either with Maven, Ant or the Modeler) and are later filled with appropriate logic by the programmer. E.g. assuming we mapped a 'post-add' callback called 'onNewOrder' in ObjEntity 'Order', the following code will be generated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public abstract class _Order extends CayenneDataObject {
protected abstract void onNewOrder();
}
public class Order extends _Order {
@Override
protected void onNewOrder() {
//TODO: implement onNewOrder
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As <code>onNewOrder()</code> is already declared in the mapping, it does not need to be registered explicitly. Implementing the method in subclass to do something meaningful is all that is required at this point.</p>
</div>
<div class="paragraph">
<p>As a rule callback methods do not have any knowledge of the outside application, and can only access the state of the object itself and possibly the state of other persistent objects via object’s own ObjectContext.</p>
</div>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> Validation and callbacks: There is a clear overlap in functionality between object callbacks and <code>DataObject.validateForX()</code> methods. In the future validation may be completely superceeded by callbacks. It is a good idea to use "validateForX" strictly for validation (or not use it at all). Updating the state before commit should be done via callbacks. </td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect3">
<h4 id="callbacks-on-non-persistent-listeners"><a class="anchor" href="#callbacks-on-non-persistent-listeners"></a>Callbacks on Non-Persistent Listeners</h4>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> While listener callback methods can be declared in the Modeler (at least as of this wrting), which ensures their automatic registration in runtime, there’s a big downside to it. The power of the listeners lies in their complete separation from the XML mapping. The mapping once created, can be reused in different contexts each having a different set of listeners. Placing a Java class of the listener in the XML mapping, and relying on Cayenne to instantiate the listeners severly limits mapping reusability. Further down in this chapter we’ll assume that the listener classes are never present in the DataMap and are registered via API. </td>
</tr>
</tbody>
</table>
</div>
<div class="paragraph">
<p>A listener is simply some application class that has one or more annotated callback methods. A callback method signature should be <code>void someMethod(SomePersistentType object)</code>. It can be public, private, protected or use default access:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java"> public class OrderListener {
@PostAdd(Order.class)
public void setDefaultsForNewOrder(Order o) {
o.setCreatedOn(new Date());
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notice that the example above contains an annotation on the callback method that defines the type of the event this method should be called for. Before we go into annotation details, we’ll show how to create and register a listener with Cayenne. It is always a user responsibility to register desired application listeners, usually right after ServerRuntime is started. Here is an example:</p>
</div>
<div class="paragraph">
<p>First let’s define 2 simple listeners.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Listener1 {
@PostAdd(MyEntity.class)
void postAdd(Persistent object) {
// do something
}
}
public class Listener2 {
@PostRemove({ MyEntity1.class, MyEntity2.class })
void postRemove(Persistent object) {
// do something
}
@PostUpdate({ MyEntity1.class, MyEntity2.class })
void postUpdate(Persistent object) {
// do something
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Ignore the annotations for a minute. The important point here is that the listeners are arbitrary classes unmapped and unknown to Cayenne, that contain some callback methods. Now let’s register them with runtime:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">ServerRuntime runtime = ...
LifecycleCallbackRegistry registry =
runtime.getDataDomain().getEntityResolver().getCallbackRegistry();
registry.addListener(new Listener1());
registry.addListener(new Listener2());</code></pre>
</div>
</div>
<div class="paragraph">
<p>Listeners in this example are very simple. However they don’t have to be. Unlike Persistent objects, normally listeners initialization is managed by the application code, not Cayenne, so listeners may have knowledge of various application services, operation transactional context, etc. Besides a single listener can apply to multiple entities. As a consequence their callbacks can do more than just access a single ObjectContext.</p>
</div>
<div class="paragraph">
<p>Now let’s discuss the annotations. There are eight annotations exactly matching the names of eight lifecycle events. A callback method in a listener should be annotated with at least one, but possibly with more than one of them. Annotation itself defines what event the callback should react to. Annotation parameters are essentially an entity filter, defining a subset of ObjEntities whose events we are interested in:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// this callback will be invoked on PostRemove event of any object
// belonging to MyEntity1, MyEntity2 or their subclasses
@PostRemove({ MyEntity1.class, MyEntity2.class })
void postRemove(Persistent object) {
...
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// similar example with multipe annotations on a single method
// each matching just one entity
@PostPersist(MyEntity1.class)
@PostRemove(MyEntity1.class)
@PostUpdate(MyEntity1.class)
void postCommit(MyEntity1 object) {
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As shown above, "value" (the implicit annotation parameter) can contain one or more entity classes. Only these entities' events will result in callback invocation. There’s also another way to match entities - via custom annotations. This allows to match any number of entities without even knowing what they are. Here is an example. We’ll first define a custom annotation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Tag {
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now we can define a listener that will react to events from ObjEntities annotated with this annotation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Listener3 {
@PostAdd(entityAnnotations = Tag.class)
void postAdd(Persistent object) {
// do something
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As you see we don’t have any entities yet, still we can define a listener that does something useful. Now let’s annotate some entities:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">@Tag
public class MyEntity1 extends _MyEntity1 {
}
@Tag
public class MyEntity2 extends _MyEntity2 {
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="combining-listeners-with-datachannelfilters"><a class="anchor" href="#combining-listeners-with-datachannelfilters"></a>Combining Listeners with DataChannelFilters</h4>
<div class="paragraph">
<p>A final touch in the listeners design is preserving the state of the listener within a single select or commit, so that events generated by multiple objects can be collected and processed all together. To do that you will need to implement a <code>DataChannelFilter</code>, and add some callback methods to it. They will store their state in a ThreadLocal variable of the filter. Here is an example filter that does something pretty meaningless - counts how many total objects were committed. However it demonstrates the important pattern of aggregating multiple events and presenting a combined result:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class CommittedObjectCounter implements DataChannelFilter {
private ThreadLocal&lt;int[]&gt; counter;
@Override
public void init(DataChannel channel) {
counter = new ThreadLocal&lt;int[]&gt;();
}
@Override
public QueryResponse onQuery(ObjectContext originatingContext, Query query, DataChannelFilterChain filterChain) {
return filterChain.onQuery(originatingContext, query);
}
@Override
public GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType,
DataChannelFilterChain filterChain) {
// init the counter for the current commit
counter.set(new int[1]);
try {
return filterChain.onSync(originatingContext, changes, syncType);
} finally {
// process aggregated result and release the counter
System.out.println("Committed " + counter.get()[0] + " object(s)");
counter.set(null);
}
}
@PostPersist(entityAnnotations = Tag.class)
@PostUpdate(entityAnnotations = Tag.class)
@PostRemove(entityAnnotations = Tag.class)
void afterCommit(Persistent object) {
counter.get()[0]++;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now since this is both a filter and a listener, it needs to be registered as such:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">CommittedObjectCounter counter = new CommittedObjectCounter();
ServerRuntime runtime = ...
DataDomain domain = runtime.getDataDomain();
// register filter
domain.addFilter(counter);
// register listener
domain.getEntityResolver().getCallbackRegistry().addListener(counter);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="performance-tuning"><a class="anchor" href="#performance-tuning"></a>2.8. Performance Tuning</h3>
<div class="sect3">
<h4 id="prefetching"><a class="anchor" href="#prefetching"></a>Prefetching</h4>
<div class="paragraph">
<p>Prefetching is a technique that allows to bring back in one query not only the queried objects, but also objects related to them. In other words it is a controlled eager relationship resolving mechanism. Prefetching is discussed in the "Performance Tuning" chapter, as it is a powerful performance optimization method. However another common application of prefetching is to refresh stale object relationships, so more generally it can be viewed as a technique for managing subsets of the object graph.</p>
</div>
<div class="paragraph">
<p>Prefetching example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SelectQuery query = new SelectQuery(Artist.class);
// this instructs Cayenne to prefetch one of Artist's relationships
query.addPrefetch("paintings");
// query is expecuted as usual, but the resulting Artists will have
// their paintings "inflated"
List&lt;Artist&gt; artists = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>All types of relationships can be preftetched - to-one, to-many, flattened.</p>
</div>
<div class="paragraph">
<p>A prefetch can span multiple relationships:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java"> query.addPrefetch("paintings.gallery");</code></pre>
</div>
</div>
<div class="paragraph">
<p>A query can have multiple prefetches:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">query.addPrefetch("paintings");
query.addPrefetch("paintings.gallery");</code></pre>
</div>
</div>
<div class="paragraph">
<p>If a query is fetching DataRows, all "disjoint" prefetches are ignored, only "joint" prefetches are executed (see prefetching semantics discussion below for what disjoint and joint prefetches mean).</p>
</div>
<div class="sect4">
<h5 id="prefetching-semantics"><a class="anchor" href="#prefetching-semantics"></a>Prefetching Semantics</h5>
<div class="paragraph">
<p>Prefetching semantics defines a strategy to prefetch relationships. Depending on it, Cayenne would generate different types of queries. The end result is the same - query root objects with related objects fully resolved. However semantics can affect preformance, in some cases significantly. There are 3 types of prefetch semantics, all defined as constants in <code>org.apache.cayenne.query.PrefetchTreeNode</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS
PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS
PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS</code></pre>
</div>
</div>
<div class="paragraph">
<p>Each query has a default prefetch semantics, so generally users do not have to worry about changing it, except when performance is a concern, or a few special cases when a default sematics can’t produce the correct result. SelectQuery uses DISJOINT_PREFETCH_SEMANTICS by default. Semantics can be changed as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java java" data-lang="java">SelectQuery query = new SelectQuery(Artist.class);
query.addPrefetch("paintings").setSemantics(
PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);</code></pre>
</div>
</div>
<div class="paragraph">
<p>There’s no limitation on mixing different types of semantics in the same SelectQuery. Multiple prefetches each can have its own semantics.</p>
</div>
<div class="paragraph">
<p>SQLTemplate and ProcedureQuery are both using JOINT_PREFETCH_SEMANTICS and it can not be changed due to the nature of these two queries.</p>
</div>
</div>
<div class="sect4">
<h5 id="disjoint-prefetching-semantics"><a class="anchor" href="#disjoint-prefetching-semantics"></a>Disjoint Prefetching Semantics</h5>
<div class="paragraph">
<p>This semantics results in Cayenne generatiing one SQL statement for the main objects, and a separate statement for each prefetch path (hence "disjoint" - related objects are not fetched with the main query). Each additional SQL statement uses a qualifier of the main query plus a set of joins traversing the preftech path between the main and related entity.</p>
</div>
<div class="paragraph">
<p>This strategy has an advantage of efficient JVM memory use, and faster overall result processing by Cayenne, but it requires (1+N) SQL statements to be executed, where N is the number of prefetched relationships.</p>
</div>
</div>
<div class="sect4">
<h5 id="disjoint-by-id-prefetching-semantics"><a class="anchor" href="#disjoint-by-id-prefetching-semantics"></a>Disjoint-by-ID Prefetching Semantics</h5>
<div class="paragraph">
<p>This is a variation of disjoint prefetch where related objects are matched against a set of IDs derived from the fetched main objects (or intermediate objects in a multi-step prefetch). Cayenne limits the size of the generated WHERE clause, as most DBs can’t parse arbitrary large SQL. So prefetch queries are broken into smaller queries. The size of is controlled by the DI property Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY (the default number of conditions in the generated WHERE clause is 10000). Cayenne will generate (1 + N * M) SQL statements for each query using disjoint-by-ID prefetches, where N is the number of relationships to prefetch, and M is the number of queries for a given prefetch that is dependent on the number of objects in the result (ideally M = 1).</p>
</div>
<div class="paragraph">
<p>The advantage of this type of prefetch is that matching database rows by ID may be much faster than matching the qualifier of the original query. Moreover this is <strong>the only type of prefetch</strong> that can handle SelectQueries with <strong>fetch</strong> limit. Both joint and regular disjoint prefetches may produce invalid results or generate inefficient fetch-the-entire table SQL when fetch limit is in effect.</p>
</div>
<div class="paragraph">
<p>The disadvantage is that query SQL can get unwieldy for large result sets, as each object will have to have its own condition in the WHERE clause of the generated SQL.</p>
</div>
</div>
<div class="sect4">
<h5 id="joint-prefetching-semantics"><a class="anchor" href="#joint-prefetching-semantics"></a>Joint Prefetching Semantics</h5>
<div class="paragraph">
<p>Joint semantics results in a single SQL statement for root objects and any number of jointly prefetched paths. Cayenne processes in memory a cartesian product of the entities involved, converting it to an object tree. It uses OUTER joins to connect prefetched entities.</p>
</div>
<div class="paragraph">
<p>Joint is the most efficient prefetch type of the three as far as generated SQL goes. There’s always just 1 SQL query generated. Its downsides are the potentially increased amount of data that needs to get across the network between the application server and the database, and more data processing that needs to be done on the Cayenne side.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="data-rows"><a class="anchor" href="#data-rows"></a>Data Rows</h4>
<div class="paragraph">
<p>Converting result set data to Persistent objects and registering these objects in the ObjectContext can be an expensive operation compareable to the time spent running the query (and frequently exceeding it). Internally Cayenne builds the result as a list of DataRows, that are later converted to objects. Skipping the last step and using data in the form of DataRows can significantly increase performance.</p>
</div>
<div class="paragraph">
<p>DataRow is a simply a map of values keyed by their DB column name. It is a ubiqutous representation of DB data used internally by Cayenne. And it can be quite usable as is in the application in many cases. So performance sensitive selects should consider DataRows - it saves memory and CPU cycles. All selecting queries support DataRows option, e.g.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SelectQuery query = new SelectQuery(Artist.class);
query.setFetchingDataRows(true);
List&lt;DataRow&gt; rows = context.performQuery(query);</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SQLTemplate query = new SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
query.setFetchingDataRows(true);
List&lt;DataRow&gt; rows = context.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Moreover DataRows may be converted to Persistent objects later as needed. So e.g. you may implement some in-memory filtering, only converting a subset of fetched objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// you need to cast ObjectContext to DataContext to get access to 'objectFromDataRow'
DataContext dataContext = (DataContext) context;
for(DataRow row : rows) {
if(row.get("DATE_OF_BIRTH") != null) {
Artist artist = dataContext.objectFromDataRow(Artist.class, row);
// do something with Artist...
...
}
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="iterated-queries"><a class="anchor" href="#iterated-queries"></a>Iterated Queries</h4>
<div class="paragraph">
<p>While contemporary hardware may easily allow applications to fetch hundreds of thousands or even millions of objects into memory, it doesn’t mean this is always a good idea to do so. You can optimize processing of very large result sets with two techniques discussed in this and the following chapter - iterated and paginated queries.</p>
</div>
<div class="paragraph">
<p>Iterated query is not actually a special query. Any selecting query can be executed in iterated mode by the DataContext (like in the previous example, a cast to DataContext is needed). DataContext returns an object called ResultIterator that is backed by an open ResultSet. Data is read from ResultIterator one row at a time until it is exhausted. Data comes as a DataRows regardless of whether the orginating query was configured to fetch DataRows or not. A ResultIterator must be explicitly closed to avoid JDBC resource leak.</p>
</div>
<div class="paragraph">
<p>Iterated query provides constant memory performance for arbitrarily large ResultSets. This is true at least on the Cayenne end, as JDBC driver may still decide to bring the entire ResultSet into the JVM memory.</p>
</div>
<div class="paragraph">
<p>Here is a full example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// you need to cast ObjectContext to DataContext to get access to 'performIteratedQuery'
DataContext dataContext = (DataContext) context;
// create a regular query
SelectQuery q = new SelectQuery(Artist.class);
// ResultIterator operations all throw checked CayenneException
// moreover 'finally' is required to close it
try {
ResultIterator it = dataContext.performIteratedQuery(q);
try {
while(it.hasNextRow()) {
// normally we'd read a row, process its data, and throw it away
// this gives us constant memory performance
Map row = (Map) it.nextRow();
// do something with the row...
...
}
}
finally {
it.close();
}
}
catch(CayenneException e) {
e.printStackTrace();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Also common sense tells us that ResultIterators should be processed and closed as soon as possible to release the DB connection. E.g. storing open iterators between HTTP requests and for unpredictable length of time would quickly exhaust the connection pool.</p>
</div>
</div>
<div class="sect3">
<h4 id="paginated-queries"><a class="anchor" href="#paginated-queries"></a>Paginated Queries</h4>
<div class="paragraph">
<p>Enabling query pagination allows to load very large result sets in a Java app with very little memory overhead (much smaller than even the DataRows option discussed above). Moreover it is completely transparent to the application - a user gets what appears to be a list of Persistent objects - there’s no iterator to close or DataRows to convert to objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SelectQuery query = new SelectQuery(Artist.class);
query.setPageSize(50);
// the fact that result is paginated is transparent
List&lt;Artist&gt; artists = ctxt.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Having said that, DataRows option can be combined with pagination, providing the best of both worlds:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">SelectQuery query = new SelectQuery(Artist.class);
query.setPageSize(50);
query.setFetchingDataRows(true);
List&lt;DataRow&gt; rows = ctxt.performQuery(query);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The way pagination works internally, it first fetches a list of IDs for the root entity of the query. This is very fast and initially takes very little memory. Then when an object is requested at an arbitrary index in the list, this object and adjacent objects (a "page" of objects that is determined by the query pageSize parameter) are fetched together by ID. Subsequent requests to the objects of this "page" are served from memory.</p>
</div>
<div class="paragraph">
<p>An obvious limitation of pagination is that if you eventually access all objects in the list, the memory use will end up being the same as with no pagination. However it is still a very useful approach. With some lists (e.g. multi-page search results) only a few top objects are normally accessed. At the same time pagination allows to estimate the full list size without fetching all the objects. And again - it is completely transparent and looks like a normal query.</p>
</div>
</div>
<div class="sect3">
<h4 id="caching"><a class="anchor" href="#caching"></a>Caching and Fresh Data</h4>
<div class="sect4">
<h5 id="object-caching"><a class="anchor" href="#object-caching"></a>Object Caching</h5>
</div>
<div class="sect4">
<h5 id="query-result-caching"><a class="anchor" href="#query-result-caching"></a>Query Result Caching</h5>
</div>
</div>
<div class="sect3">
<h4 id="turning-off-synchronization-of-objectcontexts"><a class="anchor" href="#turning-off-synchronization-of-objectcontexts"></a>Turning off Synchronization of ObjectContexts</h4>
<div class="paragraph">
<p>By default when a single ObjectContext commits its changes, all other contexts in the same runtime receive an event that contains all the committed changes. This allows them to update their cached object state to match the latest committed data. There are however many problems with this ostensibly helpful feature. In short - it works well in environments with few contexts and in unclustered scenarios, such as single user desktop applications, or simple webapps with only a few users. More specifically:</p>
</div>
<div class="ulist">
<ul>
<li> <p>The performance of synchronization is (probably worse than) O(N) where N is the number of peer ObjectContexts in the system. In a typical webapp N can be quite large. Besides for any given context, due to locking on synchronization, context own performance will depend not only on the queries that it runs, but also on external events that it does not control. This is unacceptable in most situations.</p> </li>
<li> <p>Commit events are untargeted - even contexts that do not hold a given updated object will receive the full event that they will have to process.</p> </li>
<li> <p>Clustering between JVMs doesn’t scale - apps with large volumes of commits will quickly saturate the network with events, while most of those will be thrown away on the receiving end as mentioned above.</p> </li>
<li> <p>Some contexts may not want to be refreshed. A refresh in the middle of an operation may lead to unpredictable results.</p> </li>
<li> <p>Synchronization will interfere with optimistic locking.</p> </li>
</ul>
</div>
<div class="paragraph">
<p>So we’ve made a good case for disabling synchronization in most webapps. To do that, set to "false" the following DI property - <code><em>Constants.SERVER_CONTEXTS_SYNC_PROPERTY</em></code>, using one of the standard Cayenne DI approaches. E.g. from command line:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>$ java -Dcayenne.server.contexts_sync_strategy=false</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or by changing the standard properties Map in a custom extensions module:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class MyModule implements Module {
@Override
public void configure(Binder binder) {
binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_CONTEXTS_SYNC_PROPERTY, "false");
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="customize"><a class="anchor" href="#customize"></a>2.9. Customizing Cayenne Runtime</h3>
<div class="sect3">
<h4 id="dependency-injection-container"><a class="anchor" href="#dependency-injection-container"></a>Dependency Injection Container</h4>
<div class="paragraph">
<p>Cayenne runtime is built around a small powerful dependency injection (DI) container. Just like other popular DI technologies, such as Spring or Guice, Cayenne DI container manages sets of interdependent objects and allows users to configure them. These objects are regular Java objects. We are calling them "services" in this document to distinguish from all other objects that are not configured in the container and are not managed. DI container is responsible for service instantiation, injecting correct dependencies, maintaining service instances scope, and dispatching scope events to services.</p>
</div>
<div class="paragraph">
<p>The services are configured in special Java classes called "modules". Each module defines binding of service interfaces to implementation instances, implementation types or providers of implementation instances. There are no XML configuration files, and all the bindings are type-safe. The container supports injection into instance variables and constructor parameters based on the <code>@Inject</code> annotation. This mechanism is very close to Google Guice.</p>
</div>
<div class="paragraph">
<p>The discussion later in this chapter demonstrates a standalone DI container. But keep in mind that Cayenne already has a built-in Injector, and a set of default modules. A Cayenne user would normally only use the API below to write custom extension modules that will be loaded in that existing container when creating ServerRuntime. See "Starting and Stopping ServerRuntime" chapter for an example of passing an extension module to Cayenne.</p>
</div>
<div class="paragraph">
<p>Cayenne DI probably has ~80% of the features expected in a DI container and has no dependency on the rest of Cayenne, so in theory can be used as an application-wide DI engine. But it’s primary purpose is still to serve Cayenne. Hence there are no plans to expand it beyond Cayenne needs. It is an ideal "embedded" DI that does not interfere with Spring, Guice or any other such framework present elsewhere in the application.</p>
</div>
<div class="sect4">
<h5 id="di-bindings-api"><a class="anchor" href="#di-bindings-api"></a>DI Bindings API</h5>
<div class="paragraph">
<p>To have a working DI container, we need three things: service interfaces and classes, a module that describes service bindings, a container that loads the module, and resolves the depedencies. Let’s start with service interfaces and classes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public interface Service1 {
public String getString();
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public interface Service2 {
public int getInt();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>A service implementation using instance variable injection:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Service1Impl implements Service1 {
@Inject
private Service2 service2;
public String getString() {
return service2.getInt() + "_Service1Impl";
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Same thing, but using constructor injection:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Service1Impl implements Service1 {
private Service2 service2;
public Service1Impl(@Inject Service2 service2) {
this.service2 = service2;
}
public String getString() {
return service2.getInt() + "_Service1Impl";
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Service2Impl implements Service2 {
private int i;
public int getInt() {
return i++;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now let’s create a module implementing <code>org.apache.cayenne.tutorial.di.Module</code> interface that will contain DI configuration. A module binds service objects to keys that are reference. Binder provided by container implements fluent API to connect the key to implementation, and to configure various binding options (the options, such as scope, are demonstrated later in this chapter). The simplest form of a key is a Java Class object representing service interface. Here is a module that binds Service1 and Service2 to corresponding default implementations:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class Module1 implements Module {
public void configure(Binder binder) {
binder.bind(Service1.class).to(Service1Impl.class);
binder.bind(Service2.class).to(Service2Impl.class);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Once we have at least one module, we can create a DI container. <code>org.apache.cayenne.di.Injector</code> is the container class in Cayenne:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">Injector injector = DIBootstrap.createInjector(new Module1());</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now that we have created the container, we can obtain services from it and call their methods:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">Service1 s1 = injector.getInstance(Service1.class);
for (int i = 0; i &lt; 5; i++) {
System.out.println("S1 String: " + s1.getString());
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This outputs the following lines, demonstrating that s1 was Service1Impl and Service2 injected into it was Service2Impl:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>0_Service1Impl
1_Service1Impl
2_Service1Impl
3_Service1Impl
4_Service1Impl</code></pre>
</div>
</div>
<div class="paragraph">
<p>There are more flavors of bindings:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// binding to instance - allowing user to create and configure instance
// inside the module class
binder.bind(Service2.class).toInstance(new Service2Impl());
// binding to provider - delegating instance creation to a special
// provider class
binder.bind(Service1.class).toProvider(Service1Provider.class);
// binding to provider instance
binder.bind(Service1.class).toProviderInstance(new Service1Provider());
// multiple bindings of the same type using Key
// injection can reference the key name in annotation:
// @Inject("i1")
// private Service2 service2;
binder.bind(Key.get(Service2.class, "i1")).to(Service2Impl.class);
binder.bind(Key.get(Service2.class, "i2")).to(Service2Impl.class);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Another types of confiuguration that can be bound in the container are lists and maps. They will be discussed in the following chapters.</p>
</div>
</div>
<div class="sect4">
<h5 id="service-lifecycle"><a class="anchor" href="#service-lifecycle"></a>Service Lifecycle</h5>
<div class="paragraph">
<p>An important feature of the Cayenne DI container is instance scope. The default scope (implicitly used in all examples above) is "singleton", meaning that a binding would result in creation of only one service instance, that will be repeatedly returned from <code>Injector.getInstance(..)</code>, as well as injected into classes that declare it as a dependency.</p>
</div>
<div class="paragraph">
<p>Singleton scope dispatches a "BeforeScopeEnd" event to interested services. This event occurs before the scope is shutdown, i.e. when <code>Injector.shutdown()</code> is called. Note that the built-in Cayenne injector is shutdown behind the scenes when <code>ServerRuntime.shutdown()</code> is invoked. Services may register as listeners for this event by annotating a no-argument method with <code>@BeforeScopeEnd</code> annotation. Such method should be implemented if a service needs to clean up some resources, stop threads, etc.</p>
</div>
<div class="paragraph">
<p>Another useful scope is "no scope", meaning that every time a container is asked to provide a service instance for a given key, a new instance will be created and returned:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">binder.bind(Service2.class).to(Service2Impl.class).withoutScope();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Users can also create their own scopes, e.g. a web application request scope or a session scope. Most often than not custom scopes can be created as instances of <code>org.apache.cayenne.di.spi.DefaultScope</code> with startup and shutdown managed by the application (e.g. singleton scope is a DefaultScope managed by the Injector) .</p>
</div>
</div>
<div class="sect4">
<h5 id="overriding-services"><a class="anchor" href="#overriding-services"></a>Overriding Services</h5>
<div class="paragraph">
<p>Cayenne DI allows to override services already definied in the current module, or more commonly - some other module in the the same container. Actually there’s no special API to override a service, you’d just bind the service key again with a new implementation or provider. The last binding for a key takes precedence. This means that the order of modules is important when configuring a container. The built-in Cayenne injector ensures that Cayenne standard modules are loaded first, followed by optional user extension modules. This way the application can override the standard services in Cayenne.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="customization-strategies"><a class="anchor" href="#customization-strategies"></a>Customization Strategies</h4>
<div class="paragraph">
<p>The previous section discussed how Cayenne DI works in general terms. Since Cayenne users will mostly be dealing with an existing Injector provided by ServerRuntime, it is important to understand how to build custom extensions to a preconfigured container. As shown in "Starting and Stopping ServerRuntime" chapter, custom extensions are done by writing an aplication DI module (or multiple modules) that configures service overrides. This section shows all the configuration possibilities in detail, including changing properties of the existing services, contributing services to standard service lists and maps, and overriding service implementations. All the code examples later in this section are assumed to be placed in an application module "configure" method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class MyExtensionsModule implements Module {
public void configure(Binder binder) {
// customizations go here...
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">Module extensions = new MyExtensionsModule();
ServerRuntime runtime =
new ServerRuntime("com/example/cayenne-mydomain.xml", extensions);</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="changing-properties-of-existing-services"><a class="anchor" href="#changing-properties-of-existing-services"></a>Changing Properties of Existing Services</h5>
<div class="paragraph">
<p>Many built-in Cayenne services change their behavior based on a value of some environment property. A user may change Cayenne behavior without even knowing which services are responsible for it, but setting a specific value of a known property. Supported property names are listed in "Appendix A".</p>
</div>
<div class="paragraph">
<p>There are two ways to set service properties. The most obvious one is to pass it to the JVM with -D flag on startup. E.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre>$ java -Dcayenne.server.contexts_sync_strategy=false ...</pre>
</div>
</div>
<div class="paragraph">
<p>A second one is to contribute a property to <code>org.apache.cayenne.configuration.DefaultRuntimeProperties.properties</code> map (see the next section on how to do that). This map contains the default property values and can accept application-specific values, overrding the defaults.</p>
</div>
<div class="paragraph">
<p>Note that if a property value is a name of a Java class, when this Java class is instantiated by Cayenne, the container performs injection of instance variables. So even the dynamically specified Java classes can use @Inject annotation to get a hold of other Cayenne services.</p>
</div>
<div class="paragraph">
<p>If the same property is specified both in the command line and in the properties map, the command-line value takes precedence. The map value will be ignored. This way Cayenne runtime can be reconfigured during deployment.</p>
</div>
</div>
<div class="sect4">
<h5 id="contributing-to-service-collections"><a class="anchor" href="#contributing-to-service-collections"></a>Contributing to Service Collections</h5>
<div class="paragraph">
<p>Cayenne can be extended by adding custom objects to named maps or lists bound in DI. We are calling these lists/maps "service collections". A service collection allows things like appending a custom strategy to a list of built-in strategies. E.g. an application that needs to install a custom DbAdapter for some database type may contribute an instance of custom DbAdapterDetector to a <code>org.apache.cayenne.configuration.server.DefaultDbAdapterFactory.detectors</code> list:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">public class MyDbAdapterDetector implements DbAdapterDetector {
public DbAdapter createAdapter(DatabaseMetaData md) throws SQLException {
// check if we support this database and retun custom adapter
...
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">// since build-in list for this key is a singleton, repeated
// calls to 'bindList' will return the same instance
binder.bindList(DefaultDbAdapterFactory.DETECTORS_LIST)
.add(MyDbAdapterDetector.class);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Maps are customized using a similar <code>"bindMap"</code> method.</p>
</div>
<div class="paragraph">
<p>The names of built-in collections are listed in "Appendix B".</p>
</div>
</div>
<div class="sect4">
<h5 id="alternative-service-implementations"><a class="anchor" href="#alternative-service-implementations"></a>Alternative Service Implementations</h5>
<div class="paragraph">
<p>As mentioned above, custom modules are loaded by ServerRuntime after the built-in modules. So it is easy to redefine a built-in service in Cayenne by rebinding desired implementations or providers. To do that, first we need to know what those services to redefine are. While we describe some of them in the following sections, the best way to get a full list is to check the source code of the Cayenne version you are using and namely look in <code>org.apache.cayenne.configuration.server.ServerModule</code> - the main built-in module in Cayenne.</p>
</div>
<div class="paragraph">
<p>Now an example of overriding <code>QueryCache</code> service. The default implementation of this service is provided by <code>MapQueryCacheProvider</code>. But if we want to use <code>EhCacheQueryCache</code> (a Cayenne wrapper for the EhCache framework), we can define it like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-Java Java" data-lang="Java">binder.bind(QueryCache.class).to(EhCacheQueryCache.class);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="noteworthy-built-in-services"><a class="anchor" href="#noteworthy-built-in-services"></a>Noteworthy Built-in Services</h4>
<div class="sect4">
<h5 id="jdbceventlogger"><a class="anchor" href="#jdbceventlogger"></a>JdbcEventLogger</h5>
<div class="paragraph">
<p><code>org.apache.cayenne.log.JdbcEventLogger</code> is the service that defines logging API for Cayenne internals. It provides facilities for logging queries, commits, transactions, etc. The default implementation is <code>org.apache.cayenne.log.Slf4jJdbcEventLogger</code> that performs logging via slf4j-api library. Cayenne library includes another potentially useful logger - <code>org.apache.cayenne.log.FormattedSlf4jJdbcEventLogger</code> that produces formatted multiline SQL output that can be easier to read.</p>
</div>
</div>
<div class="sect4">
<h5 id="datasourcefactory"><a class="anchor" href="#datasourcefactory"></a>DataSourceFactory</h5>
</div>
<div class="sect4">
<h5 id="datachannelfilter"><a class="anchor" href="#datachannelfilter"></a>DataChannelFilter</h5>
</div>
<div class="sect4">
<h5 id="querycache"><a class="anchor" href="#querycache"></a>QueryCache</h5>
</div>
<div class="sect4">
<h5 id="extebdedtypes"><a class="anchor" href="#extebdedtypes"></a>ExtebdedTypes</h5>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cayenne-framework-remote-object-persistence"><a class="anchor" href="#cayenne-framework-remote-object-persistence"></a>3. Cayenne Framework - Remote Object Persistence</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="rop"><a class="anchor" href="#rop"></a>3.1. Introduction to ROP</h3>
<div class="sect3">
<h4 id="what-is-rop"><a class="anchor" href="#what-is-rop"></a>What is ROP</h4>
<div class="paragraph">
<p>"Remote Object Persistence" is a low-overhead web services-based technology that provides lightweight object persistence and query functionality to 'remote' applications. In other words it provides familiar Cayenne API to applications that do not have direct access to the database. Instead such applications would access Cayenne Web Service (CWS). A single abstract data model (expressed as Cayenne XML DataMap) is used on the server and on the client, while execution logic can be partitioned between the tiers.The following picture compares a regular Cayenne web application and a rich client application that uses remote object persistence technology:</p>
</div>
<div class="imageblock" style="text-align: center">
<div class="content">
<img src="images/remote-object-persistence.jpg" alt="remote object persistence">
</div>
</div>
<div class="paragraph">
<p>Persistence stack above consists of the following parts:</p>
</div>
<div class="ulist">
<ul>
<li> <p>ORM Tier: a server-side Cayenne Java application that directly connects to the database via JDBC.</p> </li>
<li> <p>CWS (Cayenne Web Service): A wrapper around an ORM tier that makes it accessible to remote CWS clients.</p> </li>
<li> <p>Remote Tier (aka Client Tier): A Java application that has no direct DB connection and persists its objects by connecting to remote Cayenne Web Service (CWS). Note that CWS Client doesn’t have to be a desktop application. It can be another server-side application. The word "client" means a client of Cayenne Web Service.</p> </li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="main-features"><a class="anchor" href="#main-features"></a>Main Features</h4>
<div class="ulist">
<ul>
<li> <p>Unified approach to lightweight object persistence across multiple tiers of a distributed system.</p> </li>
<li> <p>Same abstract object model on the server and on the client.</p> </li>
<li> <p>Client can "bootstrap" from the server by dynamically loading persistence metadata.</p> </li>
<li> <p>An ability to define client objects differently than the server ones, and still have seamless persistence.</p> </li>
<li> <p>Generic web service interface that doesn’t change when object model changes.</p> </li>
<li> <p>An ability to work in two modes: dedicated session mode or shared ("chat") mode when multiple remote clients collaboratively work on the same data.</p> </li>
<li> <p>Lazy object and collection faulting.</p> </li>
<li> <p>Full context lifecycle</p> </li>
<li> <p>Queries, expressions, local query caching, paginated queries.</p> </li>
<li> <p>Validation</p> </li>
<li> <p>Delete Rules</p> </li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="implementing-rop-client"><a class="anchor" href="#implementing-rop-client"></a>3.2. Implementing ROP Client</h3>
<div class="sect3">
<h4 id="system-requirements-2"><a class="anchor" href="#system-requirements-2"></a>System Requirements</h4>
</div>
<div class="sect3">
<h4 id="jar-files-and-dependencies-2"><a class="anchor" href="#jar-files-and-dependencies-2"></a>Jar Files and Dependencies</h4>
</div>
</div>
<div class="sect2">
<h3 id="implementing-rop-server"><a class="anchor" href="#implementing-rop-server"></a>3.3. Implementing ROP Server</h3>
</div>
<div class="sect2">
<h3 id="implementing-rop-client-2"><a class="anchor" href="#implementing-rop-client-2"></a>3.4. Implementing ROP Client</h3>
</div>
<div class="sect2">
<h3 id="rop-deployment"><a class="anchor" href="#rop-deployment"></a>3.5. ROP Deployment</h3>
<div class="sect3">
<h4 id="deploying-rop-server"><a class="anchor" href="#deploying-rop-server"></a>Deploying ROP Server</h4>
<div class="admonitionblock note">
<table>
<tbody>
<tr>
<td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> </td>
<td class="content"> Recent versions of Tomcat and Jetty containers (e.g. Tomcat 6 and 7, Jetty 8) contain code addressing a security concern related to "session fixation problem" by resetting the existing session ID of any request that requires BASIC authentcaition. If ROP service is protected with declarative security (see the ROP tutorial and the following chapters on security), this feature prevents the ROP client from attaching to its session, resulting in MissingSessionExceptions. To solve that you will need to either switch to an alternative security mechanism, or disable "session fixation problem" protections of the container. E.g. the later can be achieved in Tomcat 7 by adding the following context.xml file to the webapp’s META-INF/ directory: </td>
</tr>
</tbody>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-XML XML" data-lang="XML">&lt;Context&gt;
&lt;Valve className="org.apache.catalina.authenticator.BasicAuthenticator"
changeSessionIdOnAuthentication="false" /&gt;
&lt;/Context&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>(The &lt;Valve&gt; tag can also be placed within the &lt;Context&gt; in any other locations used by Tomcat to load context configurations)</p>
</div>
</div>
<div class="sect3">
<h4 id="deploying-rop-client"><a class="anchor" href="#deploying-rop-client"></a>Deploying ROP Client</h4>
</div>
<div class="sect3">
<h4 id="security"><a class="anchor" href="#security"></a>Security</h4>
</div>
</div>
<div class="sect2">
<h3 id="current-limitations"><a class="anchor" href="#current-limitations"></a>3.6. Current Limitations</h3>
</div>
</div>
</div>
<div class="sect1">
<h2 id="appendix-a-configuration-properties"><a class="anchor" href="#appendix-a-configuration-properties"></a>4. Appendix A. Configuration Properties</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Note that the property names below are defined as constants in <code>org.apache.cayenne.configuration.Constants</code> interface.</p>
</div>
<div id="configProperties" class="ulist">
<ul>
<li> <p><code>cayenne.jdbc.driver[.domain_name.node_name]</code> defines a JDBC driver class to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.</p>
<div class="ulist">
<ul>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.jdbc.url[.domain_name.node_name]</code> defines a DB URL to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.</p>
<div class="ulist">
<ul>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.jdbc.username[.domain_name.node_name]</code> defines a DB user name to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: any</p> </li>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.jdbc.password[.domain_name.node_name]</code> defines a DB password to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system</p>
<div class="ulist">
<ul>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.jdbc.min_connections[.domain_name.node_name]</code> defines the DB connection pool minimal size. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system</p>
<div class="ulist">
<ul>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.jdbc.max_connections[.domain_name.node_name]</code> defines the DB connection pool maximum size. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system</p>
<div class="ulist">
<ul>
<li> <p>Default value: none, project DataNode configuration is used</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.querycache.size</code> An integer defining the maximum number of entries in the query cache. Note that not all QueryCache providers may respect this property. MapQueryCache uses it, but the rest would use alternative configuration methods.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: any positive int value</p> </li>
<li> <p>Default value: 2000</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.server.contexts_sync_strategy</code> defines whether peer ObjectContexts should receive snapshot events after commits from other contexts. If true (<em>default</em>), the contexts would automatically synchronize their state with peers.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: true, false</p> </li>
<li> <p>Default value: true</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.server.object_retain_strategy</code> defines fetched objects retain strategy for ObjectContexts. When weak or soft strategy is used, objects retained by ObjectContext that have no local changes can potentially get garbage collected when JVM feels like doing it.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: weak, soft, hard</p> </li>
<li> <p>Default value: weak</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.server.max_id_qualifier_size</code> defines a maximum number of ID qualifiers in the WHERE clause of queries that are generated for paginated queries and for DISJOINT_BY_ID prefetch processing. This is needed to avoid hitting WHERE clause size limitations and memory usage efficiency.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: any positive int</p> </li>
<li> <p>Default value: 10000</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.service_url</code> defines the URL of the ROP server</p>
<div class="ulist">
<ul>
<li> <p>Default value: none</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.service_username</code> defines the user name for an ROP client to login to an ROP server.</p>
<div class="ulist">
<ul>
<li> <p>Default value: none</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.service_password</code> defines the password for an ROP client to login to an ROP server.</p>
<div class="ulist">
<ul>
<li> <p>Default value: none</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.service.timeout</code> a value in milliseconds for the ROP client-server connection read operation timeout</p>
<div class="ulist">
<ul>
<li> <p>Possible values: any positive long value</p> </li>
<li> <p>Default value: none</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.shared_session_name</code> defines the name of the shared session that an ROP client wants to join on an ROP server. If omitted, a dedicated session is created.</p>
<div class="ulist">
<ul>
<li> <p>Default value: none</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.channel_events</code> defines whether client-side DataChannel should dispatch events to child ObjectContexts. If set to true, ObjectContexts will receive commit events and merge changes committed by peer contexts that passed through the common client DataChannel.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: true, false</p> </li>
<li> <p>Default value: false</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.context_change_events</code> defines whether object property changes in the client context result in firing events. Client UI components can listen to these events and update the UI. Disabled by default.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: true, false</p> </li>
<li> <p>Default value: false</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.rop.context_lifecycle_events</code> defines whether object commit and rollback operations in the client context result in firing events. Client UI components can listen to these events and update the UI. Disabled by default.</p>
<div class="ulist">
<ul>
<li> <p>Possible values: true,false</p> </li>
<li> <p>Default value: false</p> </li>
</ul>
</div> </li>
<li> <p><code>cayenne.server.rop_event_bridge_factory</code> defines the name of the <code>org.apache.cayenne.event.EventBridgeFactory</code> that is passed from the ROP server to the client. I.e. server DI would provide a name of the factory, passing this name to the client via the wire. The client would instantiate it to receive events from the server. Note that this property is stored in <code>cayenne.server.rop_event_bridge_properties</code> map, not in the main <code>cayenne.properties</code>.</p>
<div class="ulist">
<ul>
<li> <p>Default value: false</p> </li>
</ul>
</div> </li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="appendix-b-service-collections"><a class="anchor" href="#appendix-b-service-collections"></a>5. Appendix B. Service Collections</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Note that the collection keys below are defined as constants in <code>org.apache.cayenne.configuration.Constants</code> interface.</p>
</div>
<table id="serviceCollections" class="tableblock frame-all grid-all spread table table-bordered">
<caption class="title">
Table 8. Service Collection Keys Present in ServerRuntime and/or ClientRuntime
</caption>
<colgroup>
<col style="width: 37.5%;">
<col style="width: 25%;">
<col style="width: 37.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Collection Property</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.properties</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>Map&lt;String,String&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Properties used by built-in Cayenne services. The keys in this map are the property names from the table in Appendix A. Separate copies of this map exist on the server and ROP client.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.adapter_detectors</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;DbAdapterDetector&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Contains objects that can discover the type of current database and install the correct DbAdapter in runtime.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.domain_filters</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;DataChannelFilter&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores DataDomain filters.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.project_locations</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;String&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores locations of the one of more project configuration files.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.default_types</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;ExtendedType&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores default adapter-agnostic ExtendedTypes. Default ExtendedTypes can be overridden / extended by DB-specific DbAdapters as well as by user-provided types configured in another colltecion (see <code>"cayenne.server.user_types"</code>).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.user_types</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;ExtendedType&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores a user-provided ExtendedTypes. This collection will be merged into a full list of ExtendedTypes and would override any ExtendedTypes defined in a default list, or by a DbAdapter.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.type_factories</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>List&lt;ExtendedTypeFactory&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores default and user-provided ExtendedTypeFactories. ExtendedTypeFactory allows to define ExtendedTypes dynamically for the whole group of Java classes. E.g. Cayenne supplies a factory to map all Enums regardless of their type.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>cayenne.server.rop_event_bridge_properties</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock"><code>Map&lt;String, String&gt;</code></p></td>
<td class="tableblock halign-left valign-middle"><p class="tableblock">Stores event bridge properties passed to the ROP client on bootstrap. This means that the map is configured by server DI, and passed to the client via the wire. The properties in this map are specific to EventBridgeFactory implementation (e.g JMS or XMPP connection prameters). One common property is <code>"cayenne.server.rop_event_bridge_factory"</code> that defines the type of the factory.</p></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect1">
<h2 id="appendix-c-expressions-bnf"><a class="anchor" href="#appendix-c-expressions-bnf"></a>6. Appendix C. Expressions BNF</h2>
<div class="sectionbody">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code>TOKENS
&lt;DEFAULT&gt; SKIP : {
" "
| "\t"
| "\n"
| "\r"
}
&lt;DEFAULT&gt; TOKEN : {
&lt;NULL: "null" | "NULL"&gt;
| &lt;TRUE: "true" | "TRUE"&gt;
| &lt;FALSE: "false" | "FALSE"&gt;
}
&lt;DEFAULT&gt; TOKEN : {
&lt;PROPERTY_PATH: &lt;IDENTIFIER&gt; ("." &lt;IDENTIFIER&gt;)*&gt;
}
&lt;DEFAULT&gt; TOKEN : {
&lt;IDENTIFIER: &lt;LETTER&gt; (&lt;LETTER&gt; | &lt;DIGIT&gt;)* (["+"])?&gt;
| &lt;#LETTER: ["_","a"-"z","A"-"Z"]&gt;
| &lt;#DIGIT: ["0"-"9"]&gt;
}
/**
* Quoted Strings, whose object value is stored in the token manager's
* "literalValue" field. Both single and double qoutes are allowed
*/&lt;DEFAULT&gt; MORE : {
"\'" : WithinSingleQuoteLiteral
| "\"" : WithinDoubleQuoteLiteral
}
&lt;WithinSingleQuoteLiteral&gt; MORE : {
&lt;ESC: "\\" (["n","r","t","b","f","\\","\'","`","\""] | (["0"-"3"])? ["0"-"7"] (["0"-"7"])?)&gt; : {
| &lt;~["\'","\\"]&gt; : {
}
&lt;WithinSingleQuoteLiteral&gt; TOKEN : {
&lt;SINGLE_QUOTED_STRING: "\'"&gt; : DEFAULT
}
&lt;WithinDoubleQuoteLiteral&gt; MORE : {
&lt;STRING_ESC: &lt;ESC&gt;&gt; : {
| &lt;~["\"","\\"]&gt; : {
}
&lt;WithinDoubleQuoteLiteral&gt; TOKEN : {
&lt;DOUBLE_QUOTED_STRING: "\""&gt; : DEFAULT
}
/**
* Integer or real Numeric literal, whose object value is stored in the token manager's
* "literalValue" field.
*/&lt;DEFAULT&gt; TOKEN : {
&lt;INT_LITERAL: ("0" (["0"-"7"])* | ["1"-"9"] (["0"-"9"])* | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+)
(["l","L","h","H"])?&gt; : {
| &lt;FLOAT_LITERAL: &lt;DEC_FLT&gt; (&lt;EXPONENT&gt;)? (&lt;FLT_SUFF&gt;)? | &lt;DEC_DIGITS&gt; &lt;EXPONENT&gt; (&lt;FLT_SUFF&gt;)?
| &lt;DEC_DIGITS&gt; &lt;FLT_SUFF&gt;&gt; : {
| &lt;#DEC_FLT: (["0"-"9"])+ "." (["0"-"9"])* | "." (["0"-"9"])+&gt;
| &lt;#DEC_DIGITS: (["0"-"9"])+&gt;
| &lt;#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+&gt;
| &lt;#FLT_SUFF: ["d","D","f","F","b","B"]&gt;
}
NON-TERMINALS
expression := orCondition &lt;EOF&gt;
orCondition := andCondition ( "or" andCondition )*
andCondition := notCondition ( "and" notCondition )*
notCondition := ( "not" | "!" ) simpleCondition
| simpleCondition
simpleCondition := &lt;TRUE&gt;
| &lt;FALSE&gt;
| scalarConditionExpression
( simpleNotCondition
| ( "=" | "==" ) scalarExpression
| ( "!=" | "&lt;&gt;" ) scalarExpression
| "&lt;=" scalarExpression
| "&lt;" scalarExpression | "&gt;" scalarExpression
| "&gt;=" scalarExpression
| "like" scalarExpression
| "likeIgnoreCase" scalarExpression
| "in" ( namedParameter | "(" scalarCommaList ")" )
| "between" scalarExpression "and" scalarExpression
)?
simpleNotCondition := ( "not" | "!" )
( "like" scalarExpression
| "likeIgnoreCase" scalarExpression
| "in" ( namedParameter | "(" scalarCommaList ")" )
| "between" scalarExpression "and" scalarExpression
)
scalarCommaList := ( scalarConstExpression ( "," scalarConstExpression )* )
scalarConditionExpression := scalarNumericExpression
| &lt;SINGLE_QUOTED_STRING&gt;
| &lt;DOUBLE_QUOTED_STRING&gt;
| &lt;NULL&gt;
scalarExpression := scalarConditionExpression
| &lt;TRUE&gt;
| &lt;FALSE&gt;
scalarConstExpression := &lt;SINGLE_QUOTED_STRING&gt;
| &lt;DOUBLE_QUOTED_STRING&gt;
| namedParameter
| &lt;INT_LITERAL&gt;
| &lt;FLOAT_LITERAL&gt;
| &lt;TRUE&gt;
| &lt;FALSE&gt;
scalarNumericExpression := multiplySubtractExp
( "+" multiplySubtractExp | "-" multiplySubtractExp )*
multiplySubtractExp := numericTerm ( "*" numericTerm | "/" numericTerm )*
numericTerm := ( "+" )? numericPrimary
| "-" numericPrimary
numericPrimary := "(" orCondition ")"
| pathExpression
| namedParameter
| &lt;INT_LITERAL&gt;
| &lt;FLOAT_LITERAL&gt;
namedParameter := "$" &lt;PROPERTY_PATH&gt;
pathExpression := ( &lt;PROPERTY_PATH&gt;
| "obj:" &lt;PROPERTY_PATH&gt;
| "db:" &lt;PROPERTY_PATH&gt;
| "enum:" &lt;PROPERTY_PATH&gt; )</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="list-of-tables"><a class="anchor" href="#list-of-tables"></a>7. List of tables</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li> <p><a href="#tablecgen">cgen required parameters</a></p> </li>
<li> <p><a href="#cgenOptional">cgen optional parameters</a></p> </li>
<li> <p><a href="#cdbgenTable">cdbgen required parameters</a></p> </li>
<li> <p><a href="#cdbgenOptionl">cdbgen optional parameters</a></p> </li>
<li> <p><a href="#cdbimportTable">cdbimport parameters</a></p> </li>
<li> <p><a href="#persistenceStates">Persistence States</a></p> </li>
<li> <p><a href="#lifecycleEvent">Lifecycle Event Types</a></p> </li>
<li> <p><a href="#congigProperties">Configuration Properties Recognized by ServerRuntime and/or ClientRuntime</a></p> </li>
<li> <p><a href="#serviceCollections">Service Collection Keys Present in ServerRuntime and/or ClientRuntime</a></p> </li>
</ul>
</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/3.1/getting-started-rop/'>
<span class="d-block d-md-none text-muted">Next: </span>
Next: Cayenne Getting Started ROP
<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>