blob: cc69d8681b0e50ffba9c14d861f0db1f9c54fe9d [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;6.&nbsp;Getting started with persistent objects</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 3.1 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 3.1"><link rel="home" href="index.html" title="Getting Started with Cayenne"><link rel="up" href="getting-started-part3.html" title="Part&nbsp;III.&nbsp;Learning Cayenne API"><link rel="prev" href="ch05.html" title="Chapter&nbsp;5.&nbsp;Getting started with ObjectContext"><link rel="next" href="ch07.html" title="Chapter&nbsp;7.&nbsp;Selecting Objects"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-7036673-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.3.1 (3.1)</th><th align="center">Chapter&nbsp;6.&nbsp;Getting started with persistent objects</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch05.html">Prev</a>&nbsp;</td><th width="60%" align="center"><a accesskey="u" href="getting-started-part3.html">Part&nbsp;III.&nbsp;Learning Cayenne API</a></th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch07.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter&nbsp;6.&nbsp;Getting started with persistent objects"><div class="titlepage"><div><div><h2 class="title"><a name="d0e361"></a>Chapter&nbsp;6.&nbsp;Getting started with persistent objects</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch06.html#customizing-persistent-objects">Inspecting and Customizing Persistent Objects</a></span></dt><dt><span class="section"><a href="ch06.html#create-new-objects">Create New Objects</a></span></dt></dl></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" title="Inspecting and Customizing Persistent Objects"><div class="titlepage"><div><div><h2 class="title"><a name="customizing-persistent-objects"></a>Inspecting and Customizing Persistent Objects</h2></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.
org.example.cayenne.persistent.Artist), you'll see that it extends a class with the name
that starts with underscore (org.example.cayenne.persistent.auto._Artist), which in turn
extends from org.apache.cayenne.CayenneDataObject. Splitting each persistent class into
user-customizable subclass (Xyz) and a generated superclass (_Xyz) 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" title="Create New Objects"><div class="titlepage"><div><div><h2 class="title"><a name="create-new-objects"></a>Create New Objects</h2></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 ObjectContext using "newObject" method. Objects <span class="bold"><strong>must</strong></span> be registered with DataContext 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 "Gallery" 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 estabslished in both directions (e.g.
picasso.addToPaintings(girl) has exactly the same effect as
girl.setToArtist(picasso)).</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="programlisting">org.apache.cayenne.configuration.XMLDataChannelDescriptorLoader load
INFO: Loading XML configuration resource from file:cayenne-project.xml
...
INFO: Opening connection: jdbc:derby:memory:testdb;create=true
Login: null
Password: *******
INFO: +++ Connecting: SUCCESS.
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
"CreateIfNoSchemaStrategy"). 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="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch05.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="getting-started-part3.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;5.&nbsp;Getting started with ObjectContext&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;7.&nbsp;Selecting Objects</td></tr></table></div></body></html>