blob: ab1aac19824bfc84062a7f43a45e3756ddbc0a03 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title xmlns:d="http://docbook.org/ns/docbook">Chapter&nbsp;3.&nbsp;Learning Cayenne API</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 4.0 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 4.0"><link rel="home" href="index.html" title="Getting Started with Cayenne"><link rel="up" href="index.html" title="Getting Started with Cayenne"><link rel="prev" href="getting-started-part2.html" title="Chapter&nbsp;2.&nbsp;Learning mapping basics"><link rel="next" href="getting-started-part4.html" title="Chapter&nbsp;4.&nbsp;Converting to Web Application"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-7036673-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.4.0 (4.0.M5)</th><th align="center">Chapter&nbsp;3.&nbsp;Learning Cayenne API</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="getting-started-part2.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="getting-started-part4.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="getting-started-part3"></a>Chapter&nbsp;3.&nbsp;Learning Cayenne API</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="getting-started-part3.html#d0e414">Getting started with ObjectContext</a></span></dt><dt><span class="section"><a href="getting-started-part3.html#d0e485">Getting started with persistent objects</a></span></dt><dt><span class="section"><a href="getting-started-part3.html#d0e565">Selecting Objects</a></span></dt><dt><span class="section"><a href="getting-started-part3.html#d0e610">Deleting Objects</a></span></dt></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="d0e414"></a>Getting started with ObjectContext</h2></div></div></div><p>In this section we'll write a simple main class to run our application, and get a brief
introduction to Cayenne ObjectContext.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="creating-main-class"></a>Creating the Main Class</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>In IDEA create a new class called "<code class="code">Main</code>" in the "<code class="code">org.example.cayenne</code>"
package.</p></li><li class="listitem"><p>Create a standard "main" method to make it a runnable
class:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">package</span> org.example.cayenne;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Main {
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">static</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> main(String[] args) {
}
}</pre></li><li class="listitem"><p>The first thing you need to be able to access the database is to create a
<code class="code">ServerRuntime</code> object (which is essentially a wrapper around Cayenne stack) and
use it to obtain an instance of an
<code class="code">ObjectContext</code>.</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">package</span> org.example.cayenne;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> org.apache.cayenne.ObjectContext;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> org.apache.cayenne.configuration.server.ServerRuntime;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Main {
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">static</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> main(String[] args) {
ServerRuntime cayenneRuntime = ServerRuntime.builder()
.addConfig(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"cayenne-project.xml"</span>)
.build();
ObjectContext context = cayenneRuntime.newContext();
}
}</pre><p><code class="code">ObjectContext</code> is an isolated "session" in Cayenne that provides all needed API
to work with data. ObjectContext has methods to execute queries and manage
persistent objects. We'll discuss them in the following sections. When the first
ObjectContext is created in the application, Cayenne loads XML mapping files and
creates a shared access stack that is later reused by other ObjectContexts.
</p></li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="runnning-app"></a>Running Application</h3></div></div></div><p>Let's check what happens when you run the application. But before we do that we need
to add another dependency to the <code class="code">pom.xml</code> - Apache Derby, our embedded database engine.
The following piece of XML needs to be added to the
<code class="code">&lt;dependencies&gt;...&lt;/dependencies&gt;</code> section, where we already have Cayenne
jars:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;groupId&gt;</span>org.apache.derby<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;artifactId&gt;</span>derby<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;version&gt;</span>10.13.1.1<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;/version&gt;</span>
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">&lt;/dependency&gt;</span></pre><p>Now
we are ready to run. Right click the "Main" class in IDEA and select "Run 'Main.main()'".
</p><p>
<span class="inlinemediaobject"><img src="images/idea-file-run-menu.png"></span>
</p><p>
In the console you'll see output similar to this, indicating that Cayenne stack has been started:
</p><pre class="screen">INFO: Loading XML configuration resource from file:/.../cayenne-project.xml
INFO: Loading XML DataMap resource from file:/.../datamap.map.xml
INFO: loading user name and password.
INFO: Connecting to 'jdbc:derby:memory:testdb;create=true' as 'null'
INFO: +++ Connecting: SUCCESS.
INFO: setting DataNode 'datanode' as default, used by all unlinked DataMaps</pre><p>
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">How to Configure Cayenne Logging</h3><p>Follow the instructions in the logging chapter to tweak verbosity of the logging output.</p></div><p>
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="d0e485"></a>Getting started with persistent objects</h2></div></div></div><p>In this chapter we'll learn about persistent objects, how to customize them and how to
create and save them in DB.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="customizing-persistent-objects"></a>Inspecting and Customizing Persistent Objects</h3></div></div></div><p>Persistent classes in Cayenne implement a DataObject interface. If you inspect any of
the classes generated earlier in this tutorial (e.g.
<code class="code">org.example.cayenne.persistent.Artist</code>), you'll see that it extends a class with the name
that starts with underscore (<code class="code">org.example.cayenne.persistent.auto._Artist</code>), which in turn
extends from <code class="code">org.apache.cayenne.CayenneDataObject</code>. Splitting each persistent class into
user-customizable subclass (<code class="code">Xyz</code>) and a generated superclass (<code class="code">_Xyz</code>) is a useful technique
to avoid overwriting the custom code when refreshing classes from the mapping
model.</p><p>Let's for instance add a utility method to the Artist class that sets Artist date of
birth, taking a string argument for the date. It will be preserved even if the model
changes later:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">package</span> org.example.cayenne.persistent;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> java.text.ParseException;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> java.text.SimpleDateFormat;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> java.util.Date;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">import</span> org.example.cayenne.persistent.auto._Artist;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Artist <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">extends</span> _Artist {
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">static</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">final</span> String DEFAULT_DATE_FORMAT = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"yyyyMMdd"</span>;
<strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/**
* Sets date of birth using a string in format yyyyMMdd.
*/</strong>
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> setDateOfBirthString(String yearMonthDay) {
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">if</span> (yearMonthDay == null) {
setDateOfBirth(null);
} <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">else</span> {
Date date;
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">try</span> {
date = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> SimpleDateFormat(DEFAULT_DATE_FORMAT)
.parse(yearMonthDay);
} <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">catch</span> (ParseException e) {
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">throw</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> IllegalArgumentException(
<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"A date argument must be in format '"</span>
+ DEFAULT_DATE_FORMAT + <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"': "</span> + yearMonthDay);
}
setDateOfBirth(date);
}
}
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="create-new-objects"></a>Create New Objects</h3></div></div></div><p>Now we'll create a bunch of objects and save them to the database. An object is
created and registered with <code class="code">ObjectContext</code> using "<code class="code">newObject</code>" method. Objects <span class="bold"><strong>must</strong></span> be registered with <code class="code">DataContext</code> to be persisted and to
allow setting relationships with other objects. Add this code to the "main" method of
the Main class:</p><pre class="programlisting">Artist picasso = context.newObject(Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);
picasso.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Pablo Picasso"</span>);
picasso.setDateOfBirthString(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"18811025"</span>);</pre><p>Note that at this point "picasso" object is only stored in memory and is not saved in
the database. Let's continue by adding a Metropolitan Museum "<code class="code">Gallery</code>" object and a few
Picasso "Paintings":</p><pre class="programlisting">Gallery metropolitan = context.newObject(Gallery.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);
metropolitan.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Metropolitan Museum of Art"</span>);
Painting girl = context.newObject(Painting.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);
girl.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Girl Reading at a Table"</span>);
Painting stein = context.newObject(Painting.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);
stein.setName(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Gertrude Stein"</span>);</pre><p>Now we can link the objects together, establishing relationships. Note that in each
case below relationships are automatically established in both directions (e.g.
<code class="code">picasso.addToPaintings(girl)</code> has exactly the same effect as
<code class="code">girl.setToArtist(picasso)</code>).</p><pre class="programlisting">picasso.addToPaintings(girl);
picasso.addToPaintings(stein);
girl.setGallery(metropolitan);
stein.setGallery(metropolitan);</pre><p>Now lets save all five new objects, in a single method call:</p><pre class="programlisting">context.commitChanges();</pre><p>Now you can run the application again as described in the previous chapter. The new
output will show a few actual DB operations:</p><pre class="screen">org.apache.cayenne.configuration.XMLDataChannelDescriptorLoader load
INFO: Loading XML configuration resource from file:cayenne-project.xml
...
INFO: Connecting to 'jdbc:derby:memory:testdb;create=true' as 'null'
INFO: +++ Connecting: SUCCESS.
INFO: setting DataNode 'datanode' as default, used by all unlinked DataMaps
INFO: Detected and installed adapter: org.apache.cayenne.dba.derby.DerbyAdapter
INFO: --- transaction started.
INFO: No schema detected, will create mapped tables
INFO: CREATE TABLE GALLERY (ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID))
INFO: CREATE TABLE ARTIST (DATE_OF_BIRTH DATE, ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID))
INFO: CREATE TABLE PAINTING (ARTIST_ID INTEGER, GALLERY_ID INTEGER, ID INTEGER NOT NULL,
NAME VARCHAR (200), PRIMARY KEY (ID))
INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (ARTIST_ID) REFERENCES ARTIST (ID)
INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (GALLERY_ID) REFERENCES GALLERY (ID)
INFO: CREATE TABLE AUTO_PK_SUPPORT (
TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME))
INFO: DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ('ARTIST', 'GALLERY', 'PAINTING')
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('ARTIST', 200)
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('GALLERY', 200)
INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('PAINTING', 200)
INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'ARTIST']
INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'GALLERY']
INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'PAINTING']
INFO: INSERT INTO GALLERY (ID, NAME) VALUES (?, ?)
INFO: [batch bind: 1-&gt;ID:200, 2-&gt;NAME:'Metropolitan Museum of Art']
INFO: === updated 1 row.
INFO: INSERT INTO ARTIST (DATE_OF_BIRTH, ID, NAME) VALUES (?, ?, ?)
INFO: [batch bind: 1-&gt;DATE_OF_BIRTH:'1881-10-25 00:00:00.0', 2-&gt;ID:200, 3-&gt;NAME:'Pablo Picasso']
INFO: === updated 1 row.
INFO: INSERT INTO PAINTING (ARTIST_ID, GALLERY_ID, ID, NAME) VALUES (?, ?, ?, ?)
INFO: [batch bind: 1-&gt;ARTIST_ID:200, 2-&gt;GALLERY_ID:200, 3-&gt;ID:200, 4-&gt;NAME:'Gertrude Stein']
INFO: [batch bind: 1-&gt;ARTIST_ID:200, 2-&gt;GALLERY_ID:200, 3-&gt;ID:201, 4-&gt;NAME:'Girl Reading at a Table']
INFO: === updated 2 rows.
INFO: +++ transaction committed.
</pre><p>So first Cayenne creates the needed tables (remember, we used
"<code class="code">CreateIfNoSchemaStrategy</code>"). Then it runs a number of inserts, generating primary keys
on the fly. Not bad for just a few lines of code.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="d0e565"></a>Selecting Objects</h2></div></div></div><p>This chapter shows how to select objects from the database using <code class="code">ObjectSelect</code> query. </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="introducing-select-query"></a>Introducing ObjectSelect</h3></div></div></div><p>It was shown before how to persist new objects. Cayenne queries are used to access
already saved objects. The primary query type used for selecting objects is <code class="code">ObjectSelect</code>.
It can be mapped in CayenneModeler or created
via the API. We'll use the latter approach in this section. We don't have too much data
in the database yet, but we can still demonstrate the main principles below.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Select all paintings (the code, and the log output it generates):</p></li></ul></div><pre class="programlisting">List&lt;Painting&gt; paintings1 = ObjectSelect.query(Painting.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).select(context); </pre><pre class="screen">INFO: SELECT t0.GALLERY_ID, t0.ARTIST_ID, t0.NAME, t0.ID FROM PAINTING t0
INFO: === returned 2 rows. - took 18 ms.</pre><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Select paintings that start with "<code class="code">gi</code>", ignoring case:</p></li></ul></div><pre class="programlisting">List&lt;Painting&gt; paintings2 = ObjectSelect.query(Painting.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>)
.where(Painting.NAME.likeIgnoreCase(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"gi%"</span>)).select(context); </pre><pre class="screen">INFO: SELECT t0.GALLERY_ID, t0.NAME, t0.ARTIST_ID, t0.ID FROM PAINTING t0 WHERE UPPER(t0.NAME) LIKE UPPER(?)
[bind: 1-&gt;NAME:'gi%'] - prepared in 6 ms.
INFO: === returned 1 row. - took 18 ms.</pre><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Select all paintings done by artists who were born more than a 100 years
ago:</p></li></ul></div><pre class="programlisting">Calendar c = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> GregorianCalendar();
c.set(c.get(Calendar.YEAR) - <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">100</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">1</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>);
List&lt;Painting&gt; paintings3 = ObjectSelect.query(Painting.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>)
.where(Painting.ARTIST.dot(Artist.DATE_OF_BIRTH).lt(c.getTime()))
.select(context); </pre><pre class="screen">INFO: SELECT t0.GALLERY_ID, t0.NAME, t0.ARTIST_ID, t0.ID FROM PAINTING t0 JOIN ARTIST t1 ON (t0.ARTIST_ID = t1.ID)
WHERE t1.DATE_OF_BIRTH &lt; ? [bind: 1-&gt;DATE_OF_BIRTH:'1911-01-01 00:00:00.493'] - prepared in 7 ms.
INFO: === returned 2 rows. - took 25 ms.</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="d0e610"></a>Deleting Objects</h2></div></div></div><p>This chapter explains how to model relationship delete rules and how to delete individual
objects as well as sets of objects. Also demonstrated the use of Cayenne class to run a
query.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="setup-delete-rules"></a>Setting Up Delete Rules</h3></div></div></div><p>Before we discuss the API for object deletion, lets go back to CayenneModeler and set
up some delete rules. Doing this is optional but will simplify correct handling of the
objects related to deleted objects.</p><p>In the Modeler go to "Artist" ObjEntity, "Relationships" tab and select "Cascade" for
the "paintings" relationship delete rule:</p><p><span class="inlinemediaobject"><img src="images/modeler-deleterule.png"></span>
</p><p>Repeat this step for other relationships:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>For Gallery set "paintings" relationship to be "Nullify", as a painting can
exist without being displayed in a gallery.</p></li><li class="listitem"><p>For Painting et both relationships rules to "Nullify".</p></li></ul></div><p>Now save the mapping.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="deleting-objects"></a>Deleting Objects</h3></div></div></div><p>While deleting objects is possible via SQL, qualifying a delete on one or more IDs, a
more common way in Cayenne (or ORM in general) is to get a hold of the object first, and
then delete it via the context. Let's use utility class Cayenne to find an
artist:</p><pre class="programlisting">Artist picasso = ObjectSelect.query(Artist.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).where(Artist.NAME.eq(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"Pablo Picasso"</span>)).selectOne(context);</pre><p>Now let's delete the artist:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">if</span> (picasso != null) {
context.deleteObject(picasso);
context.commitChanges();
}</pre><p>Since we set up "Cascade" delete rule for the Artist.paintings relationships, Cayenne
will automatically delete all paintings of this artist. So when your run the app you'll
see this output:</p><pre class="screen">INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
WHERE t0.NAME = ? [bind: 1-&gt;NAME:'Pablo Picasso'] - prepared in 6 ms.
INFO: === returned 1 row. - took 18 ms.
INFO: +++ transaction committed.
INFO: --- transaction started.
INFO: DELETE FROM PAINTING WHERE ID = ?
INFO: [batch bind: 1-&gt;ID:200]
INFO: [batch bind: 1-&gt;ID:201]
INFO: === updated 2 rows.
INFO: DELETE FROM ARTIST WHERE ID = ?
INFO: [batch bind: 1-&gt;ID:200]
INFO: === updated 1 row.
INFO: +++ transaction committed.</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="getting-started-part2.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;<a accesskey="n" href="getting-started-part4.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;2.&nbsp;Learning mapping basics&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;4.&nbsp;Converting to Web Application</td></tr></table></div></body></html>