Author: aadamchik
Date: Tue Feb 19 17:18:30 2013
New Revision: 1447826

URL: http://svn.apache.org/r1447826
Log:
docs

* NamedQuery
* Custom queries
* java code listings

(cherry picked from commit 57676a27cd6f8feec6d102028a6e8eb0066c7de7)

Modified:
    
cayenne/main/branches/STABLE-3.1/docs/docbook/cayenne-guide/src/docbkx/queries.xml

Modified: 
cayenne/main/branches/STABLE-3.1/docs/docbook/cayenne-guide/src/docbkx/queries.xml
URL: 
http://svn.apache.org/viewvc/cayenne/main/branches/STABLE-3.1/docs/docbook/cayenne-guide/src/docbkx/queries.xml?rev=1447826&r1=1447825&r2=1447826&view=diff
==============================================================================
--- 
cayenne/main/branches/STABLE-3.1/docs/docbook/cayenne-guide/src/docbkx/queries.xml
 (original)
+++ 
cayenne/main/branches/STABLE-3.1/docs/docbook/cayenne-guide/src/docbkx/queries.xml
 Tue Feb 19 17:18:30 2013
@@ -31,7 +31,7 @@
 List&lt;Artist> objects = context.performQuery(query);</programlisting>This
             returned all rows in the "ARTIST" table. If the logs were turned 
on, you might see the
             following SQL
-            printed:<programlisting>INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, 
t0.ID FROM ARTIST t0
+            printed:<programlisting language="java">INFO: SELECT 
t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
 INFO: === returned 5 row. - took 5 ms.</programlisting></para>
         <para>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
@@ -41,16 +41,16 @@ INFO: === returned 5 row. - took 5 ms.</
         ExpressionFactory.likeExp(Artist.NAME_PROPERTY, "Pablo%"));
 List&lt;Artist> objects = context.performQuery(query);</programlisting>The
             SQL will look different this
-            time:<programlisting>INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID 
FROM ARTIST t0 WHERE t0.NAME LIKE ?
+            time:<programlisting language="java">INFO: SELECT 
t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 WHERE t0.NAME LIKE ?
 [bind: 1->NAME:'Pablo%']
 INFO: === returned 1 row. - took 6 ms.</programlisting></para>
         <para>SelectQuery allows to append parts of qualifier to
-            self:<programlisting>SelectQuery query = new 
SelectQuery(Artist.class);
+            self:<programlisting language="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));</programlisting></para>
         <para>To order the results of SelectQuery, one or more Orderings can 
be applied. Ordering
             were already discussed earlier.
-            E.g.:<programlisting>SelectQuery query = new 
SelectQuery(Artist.class);
+            E.g.:<programlisting language="java">SelectQuery query = new 
SelectQuery(Artist.class);
 
 // create Ordering object explicitly
 query.addOrdering(new Ordering(Artist.DATE_OF_BIRTH_PROPERTY, 
SortOrder.DESCENDING));
@@ -68,7 +68,7 @@ query.addOrdering(Artist.NAME_PROPERTY, 
         <para>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):<programlisting>EJBQLQuery query = new 
EJBQLQuery("select a FROM Artist a");</programlisting></para>
+            language):<programlisting language="java">EJBQLQuery query = new 
EJBQLQuery("select a FROM Artist a");</programlisting></para>
         <para>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.</para>
@@ -95,7 +95,7 @@ for(Object[] artistWithCount : result) {
             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:<programlisting>EJBQLQuery query = new EJBQLQuery("select 
a.name FROM Artist a");
+            scalars:<programlisting language="java">EJBQLQuery query = new 
EJBQLQuery("select a.name FROM Artist a");
 List&lt;String> names = context.performQuery(query);</programlisting>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:<itemizedlist>
@@ -202,7 +202,7 @@ query.setParameters(Collections.singleto
                     this or other forms of <code>#bind</code> instead of 
inserting them
                     inline.</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#bind(value)
+                <programlisting language="java">#bind(value)
 #bind(value jdbcType)
 #bind(value jdbcType scale)</programlisting>
                 <para><emphasis role="italic">Arguments:</emphasis>
@@ -225,12 +225,12 @@ query.setParameters(Collections.singleto
                     </itemizedlist></para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#bind($xyz)
+                    >Usage</emphasis>:<programlisting 
language="java">#bind($xyz)
 #bind('str')
 #bind($xyz 'VARCHAR')
 #bind($xyz 'DECIMAL' 2)</programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>update ARTIST set NAME 
= #bind($name) where ID = #bind($id)</programlisting></para>
+                    example:</emphasis><programlisting language="java">update 
ARTIST set NAME = #bind($name) where ID = #bind($id)</programlisting></para>
             </section>
             <section>
                 <title>#bindEqual</title>
@@ -243,37 +243,37 @@ query.setParameters(Collections.singleto
                     SQL would look like "<code>IS NULL</code>" and will be 
compilant with what the
                     DB expects.</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#bindEqual(value)
+                <programlisting language="java">#bindEqual(value)
 #bindEqual(value jdbcType)
 #bindEqual(value jdbcType scale)</programlisting>
                 <para><emphasis role="italic">Arguments: (same as 
#bind)</emphasis>
                 </para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#bindEqual($xyz)
+                    >Usage</emphasis>:<programlisting 
language="java">#bindEqual($xyz)
 #bindEqual('str')
 #bindEqual($xyz 'VARCHAR')
 #bindEqual($xyz 'DECIMAL' 2)</programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>update ARTIST set NAME 
= #bind($name) where ID #bindEqual($id)</programlisting></para>
+                    example:</emphasis><programlisting language="java">update 
ARTIST set NAME = #bind($name) where ID #bindEqual($id)</programlisting></para>
             </section>
             <section>
                 <title>#bindNotEqual</title>
                 <para>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).</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#bindNotEqual(value)
+                <programlisting language="java">#bindNotEqual(value)
 #bindNotEqual(value jdbcType)
 #bindNotEqual(value jdbcType scale)</programlisting>
                 <para><emphasis role="italic">Arguments: (same as 
#bind)</emphasis></para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#bindNotEqual($xyz)
+                    >Usage</emphasis>:<programlisting 
language="java">#bindNotEqual($xyz)
 #bindNotEqual('str')
 #bindNotEqual($xyz 'VARCHAR')
 #bindNotEqual($xyz 'DECIMAL' 2)</programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>update ARTIST set NAME 
= #bind($name) where ID #bindEqual($id)</programlisting></para>
+                    example:</emphasis><programlisting language="java">update 
ARTIST set NAME = #bind($name) where ID #bindEqual($id)</programlisting></para>
             </section>
             <section>
                 <title>#bindObjectEqual</title>
@@ -285,7 +285,7 @@ query.setParameters(Collections.singleto
                     correctly handle null object. Also notice how we are 
specifying a Velocity array
                     for multi-column PK.</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#bindObjectEqual(value columns 
idColumns)</programlisting>
+                <programlisting language="java">#bindObjectEqual(value columns 
idColumns)</programlisting>
                 <para><emphasis role="italic">Arguments:</emphasis>
                     <itemizedlist>
                         <listitem>
@@ -303,10 +303,10 @@ query.setParameters(Collections.singleto
                     </itemizedlist></para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#bindObjectEqual($a 
't0.ID' 'ID')
+                    >Usage</emphasis>:<programlisting 
language="java">#bindObjectEqual($a 't0.ID' 'ID')
 #bindObjectEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 
'PK2'])</programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>String sql = "SELECT * 
FROM PAINTING t0 WHERE #bindObjectEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) ORDER 
BY PAINTING_ID";
+                    example:</emphasis><programlisting language="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 = ....
@@ -317,15 +317,15 @@ select.setParameters(Collections.singlet
                 <para>Same as #bindObjectEqual above, only generates "not 
equal" operator for value
                     comparison (or IS NOT NULL).</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#bindObjectNotEqual(value columns 
idColumns)</programlisting>
+                <programlisting language="java">#bindObjectNotEqual(value 
columns idColumns)</programlisting>
                 <para><emphasis role="italic">Arguments: (same as 
#bindObjectEqual)</emphasis>
                 </para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#bindObjectNotEqual($a 
't0.ID' 'ID')
+                    >Usage</emphasis>:<programlisting 
language="java">#bindObjectNotEqual($a 't0.ID' 'ID')
 #bindObjectNotEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 
'PK2'])</programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>String sql = "SELECT * 
FROM PAINTING t0 WHERE #bindObjectNotEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) 
ORDER BY PAINTING_ID";
+                    example:</emphasis><programlisting language="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 = ....
@@ -338,7 +338,7 @@ select.setParameters(Collections.singlet
                     to create a DataRow (and ultimately - a persistent object) 
from an arbitrary
                     ResultSet.</para>
                 <para><emphasis role="italic">Semantics:</emphasis></para>
-                <programlisting>#result(column)
+                <programlisting language="java">#result(column)
 #result(column javaType)
 #result(column javaType alias)
 #result(column javaType alias dataRowKey)</programlisting>
@@ -373,13 +373,13 @@ select.setParameters(Collections.singlet
                     </itemizedlist></para>
                 <para>
                     <emphasis role="italic"
-                    >Usage</emphasis>:<programlisting>#result('NAME')
+                    >Usage</emphasis>:<programlisting 
language="java">#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') </programlisting></para>
                 <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>SELECT #result('ID' 
'int'), #result('NAME' 'String'), #result('DATE_OF_BIRTH' 'java.util.Date') 
FROM ARTIST</programlisting></para>
+                    example:</emphasis><programlisting language="java">SELECT 
#result('ID' 'int'), #result('NAME' 'String'), #result('DATE_OF_BIRTH' 
'java.util.Date') FROM ARTIST</programlisting></para>
             </section>
             <section>
                 <title>#chain and #chunk</title>
@@ -397,12 +397,12 @@ select.setParameters(Collections.singlet
                     entire WHERE clause should be excluded. chain/chunk allows 
to do that.</para>
                     <para>
                     <emphasis role="italic"
-                    >Semantics</emphasis>:<programlisting>#chain(operator) ... 
#end
+                    >Semantics</emphasis>:<programlisting 
language="java">#chain(operator) ... #end
 #chain(operator prefix) ... #end
 #chunk() ... #end
 #chunk(param) ... #end </programlisting></para>
                     <para><emphasis role="italic">Full
-                    example:</emphasis><programlisting>#chain('OR' 'WHERE') 
+                    example:</emphasis><programlisting 
language="java">#chain('OR' 'WHERE') 
        #chunk($name) NAME LIKE #bind($name) #end" 
        #chunk($id) ARTIST_ID > #bind($id) #end" 
 #end" </programlisting></para>
@@ -418,7 +418,7 @@ select.setParameters(Collections.singlet
                 result mapping. </para>
             <para>By default SQLTemplate is expected to return a List of 
Persistent objects of its
                 root type. This is the simple
-                case:<programlisting>SQLTemplate query = new 
SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
+                case:<programlisting language="java">SQLTemplate query = new 
SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
 
 // List of Artists
 List&lt;Artist> artists = context.performQuery(query);</programlisting>Just
@@ -426,7 +426,7 @@ List&lt;Artist> artists = context.perfor
                 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:<programlisting>String sql = SELECT t0.NAME, COUNT(1) 
FROM ARTIST t0 JOIN PAINTING t1 ON (t0.ID = t1.ARTIST_ID) "
+                Cayenne:<programlisting language="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);
 
@@ -444,7 +444,7 @@ List&lt;DataRow> rows = context.performQ
                 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:<programlisting>SQLTemplate query = new 
SQLTemplate(Painting.class, "SELECT ESTIMATED_PRICE P FROM PAINTING");
+                below:<programlisting language="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();
@@ -452,7 +452,7 @@ resultDescriptor.addColumnResult("P");
 query.setResult(resultDescriptor);
 
 // List of BigDecimals
-List&lt;BigDecimal> prices = context.performQuery(query); 
</programlisting><programlisting>SQLTemplate query = new 
SQLTemplate(Artist.class, "SELECT t0.ID, t0.NAME, t0.DATE_OF_BIRTH, 
COUNT(t1.PAINTING_ID) C " +
+List&lt;BigDecimal> prices = context.performQuery(query); 
</programlisting><programlisting language="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");
 
@@ -476,7 +476,7 @@ List&lt;Object[]> data = context.perform
                 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:<programlisting>String sql = "SELECT distinct "
+                directive:<programlisting language="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'), "
@@ -506,10 +506,10 @@ List&lt;Artist> objects = context.perfor
                 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):<programlisting>SQLTemplate query = new 
SQLTemplate("SELECT * FROM ARTIST");
+                Modeler):<programlisting language="java">SQLTemplate query = 
new SQLTemplate("SELECT * FROM ARTIST");
 query.setColumnNamesCapitalization(CapsStrategy.LOWER);
 List objects = context.performQuery(query);</programlisting></para>
-            <para>or<programlisting>SQLTemplate query = new 
SQLTemplate("SELECT * FROM ARTIST");
+            <para>or<programlisting language="java">SQLTemplate query = new 
SQLTemplate("SELECT * FROM ARTIST");
 query.setColumnNamesCapitalization(CapsStrategy.UPPER);
 List objects = context.performQuery(query); </programlisting></para>
             <para>None of this affects the generated SQL, but the resulting 
DataRows are using
@@ -525,13 +525,13 @@ List objects = context.performQuery(quer
             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:<programlisting>ProcedureQuery query = new 
ProcedureQuery("my_procedure", Artist.class);
+            else:<programlisting language="java">ProcedureQuery query = new 
ProcedureQuery("my_procedure", Artist.class);
 
 // Set "IN" parameter values
 query.addParam("p1", "abc");
 query.addParam("p2", 3000);
 
-List&lt;Artist> result = 
context.performQuery(query);</programlisting><programlisting>// here we do not 
bother with root class. 
+List&lt;Artist> result = 
context.performQuery(query);</programlisting><programlisting language="java">// 
here we do not bother with root class. 
 // Procedure name gives us needed routing information
 ProcedureQuery query = new ProcedureQuery("my_procedure");
 
@@ -544,7 +544,7 @@ QueryResponse response = context.perform
             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:<programlisting>ProcedureQuery query = new 
ProcedureQuery("my_procedure");
+            list:<programlisting language="java">ProcedureQuery query = new 
ProcedureQuery("my_procedure");
 QueryResponse response = context.performGenericQuery(query);
 
 // read OUT parameters
@@ -562,8 +562,52 @@ if(!out.isEmpty()) {
     </section>
     <section xml:id="namedquery">
         <title>NamedQuery</title>
+        <para>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:<programlisting language="java">String[] keys = new 
String[] {"loginid", "password"};
+Object[] values = new String[] {"joe", "secret"};
+
+NamedQuery query = new NamedQuery("Login", keys, values);
+
+List&lt;User> matchingUsers = context.performQuery(query); 
</programlisting></para>
     </section>
     <section xml:id="custom-queries">
         <title>Custom Queries</title>
+        <para>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. </para>
+        <para>E.g. to do something directly in the JDBC layer, you might 
subclass
+            AbstractQuery:<programlisting language="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
+            }
+        };
+    }
+}</programlisting></para>
+        <para>To delegate the actual query execution to a standard Cayenne 
query, you may subclass
+            IndirectQuery:<programlisting language="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
+    }
+}</programlisting></para>
+        <para>In fact many internal Cayenne queries are IndirectQueries, 
delegating to SelectQuery
+            or SQLTemplate after some preprocessing.</para>
     </section>
 </chapter>


Reply via email to