http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/objectContext.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/objectContext.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/objectContext.adoc
new file mode 100644
index 0000000..de13e70
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/objectContext.adoc
@@ -0,0 +1,294 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Persistent Objects and ObjectContext
+
+==== ObjectContext
+
+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:
+
+[source, java]
+----
+ObjectContext context = runtime.newContext();
+----
+
+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.
+
+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).
+
+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.
+
+
+==== Persistent Object and its Lifecycle
+
+Cayenne can persist Java objects that implement `org.apache.cayenne.Persistent 
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.
+
+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.
+
+Each persistent object belongs to a single ObjectContext, and can be in one of 
the following persistence states (as defined in 
`org.apache.cayenne.PersistenceState`) :
+
+[#persistenceStates.table.table-bordered]
+.Persistence States
+// ^.^ is not a funny face it's Asciidoctor alignment syntax (center both 
vertical and horizontal)
+[cols="^.^1,4"]
+|===
+
+|*TRANSIENT*
+|The object is not registered with an ObjectContext and will not be persisted.
+
+|*NEW*
+|The object is freshly registered in an ObjectContext, but has not been saved 
to the database yet and there is no matching database row.
+
+|*COMMITED*
+|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.
+
+|*MODIFIED*
+|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.
+
+|*HOLLOW*
+|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.
+
+|*DELETED*
+|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.
+|===
+
+==== ObjectContext Persistence API
+
+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:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+List<Artist> artists = context.performQuery(query);
+----
+
+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.
+
+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.:
+
+[source, java]
+----
+Collection<Query> queries = ... // multiple queries that need to be run 
together
+QueryChain query = new QueryChain(queries);
+
+QueryResponse response = context.performGenericQuery(query);
+----
+
+
+An application might modify selected objects. E.g.:
+
+[source, java]
+----
+Artist selectedArtist = artists.get(0);
+selectedArtist.setName("Dali");
+----
+
+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":
+
+[source, java]
+----
+context.commitChanges();
+----
+
+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.
+
+If instead of commit, we wanted to reset all changed objects to the previously 
committed state, we'd call `rollbackChanges` instead:
+
+[source, java]
+----
+context.rollbackChanges();
+----
+
+"newObject" method call creates a persistent object and sets its state to 
"NEW":
+
+[source, java]
+----
+Artist newArtist = context.newObject(Artist.class);
+newArtist.setName("Picasso");
+----
+
+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.
+
+`deleteObjects` method takes one or more Persistent objects and marks them as 
"DELETED":
+
+[source, java]
+----
+context.deleteObjects(artist1);
+context.deleteObjects(artist2, artist3, artist4);
+----
+
+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".
+
+`localObject` returns a copy of a given persistent object that is "local" to a 
given ObjectContext:
+
+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:
+
+
+[source, java]
+----
+ObjectContext editingContext = runtime.newContext();
+Artist localArtist = editingContext.localObject(artist);
+----
+
+Often an appliction needs to inspect mapping metadata. This information is 
stored in the EntityResolver object, accessible via the ObjectContext:
+
+[source, java]
+----
+EntityResolver resolver = objectContext.getEntityResolver();
+----
+
+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.
+
+==== Cayenne Helper Class
+
+There is a useful helper class called "Cayenne" (fully-qualified name 
`"org.apache.cayenne.Cayenne"`) 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) :
+
+[source, java]
+----
+long pk = Cayenne.longPKForObject(artist);
+----
+
+It also provides the reverse operation - finding an object given a known PK:
+
+[source, java]
+----
+Artist artist = Cayenne.objectForPK(context, Artist.class, 34579);
+----
+
+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:
+
+[source, java]
+----
+Artist artist = (Artist) Cayenne.objectForQuery(context, new 
SelectQuery(Artist.class));
+----
+
+Feel free to explore Cayenne class API for other useful methods.
+
+==== ObjectContext Nesting
+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.
+
+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.
+
+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.
+
+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.
+
+To create a nested context, use an instance of ServerRuntime, passing it the 
desired parent:
+
+[source, java]
+----
+ObjectContext parent = runtime.newContext();
+ObjectContext nested = runtime.newContext((DataChannel) parent);
+----
+
+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:
+
+[source, 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();
+----
+
+[source, 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();
+----
+
+==== Generic Persistent Objects
+
+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.
+
+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.
+
+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:
+
+[source, java]
+----
+DataObject generic = ((DataContext) context).newObject("GenericEntity");
+----
+
+[source, java]
+----
+DataObject generic = new CayenneDataObject();
+generic.setObjectId(new ObjectId("GenericEntity"));
+context.registerNewObject(generic);
+----
+
+SelectQuery for generic object should be created passing entity name String in 
constructor, instead of a Java class:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery("GenericEntity");
+----
+
+Use DataObject API to access and modify properties of a generic object:
+
+[source, java]
+----
+String name = (String) generic.readProperty("name");
+generic.writeProperty("name", "New Name");
+----
+
+This is how an application can obtain entity name of a generic object:
+
+[source, java]
+----
+String entityName = generic.getObjectId().getEntityName();
+----
+
+
+==== Transactions
+
+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.
+
+Two cases where transactions need to be taken into consideration are 
container-managed and application-managed transactions.
+
+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 done by setting DI configuration property defined in 
`Constants.SERVER_EXTERNAL_TX_PROPERTY` (see Appendix A). If this property is 
set to "true", Cayenne assumes that JDBC Connections obtained by runtime 
whenever that might happen are all coming from a transactional DataSource 
managed by the container. In this case Cayenne does not attempt to commit or 
rollback the connections, leaving it up to the container to do that when 
appropriate.
+
+In the second scenario, an application might need to define its own 
transaction scope that spans more than one Cayenne operation. E.g. two 
sequential commits that need to be rolled back together in case of failure. 
This can be done via `ServerRuntime.performInTransaction` method:
+
+[source, java]
+----
+Integer result = runtime.performInTransaction(() -> {
+    // commit one or more contexts
+    context1.commitChanges();
+    context2.commitChanges();
+    ....
+    // after changing some objects in context1, commit again
+    context1.commitChanges();
+    ....
+
+    // return an arbitrary result or null if we don't care about the result
+    return 5;
+});
+----
+
+When inside the transaction, current thread Transaction object can be accessed 
via a static method. E.g. here is an example that initializes transaction JDBC 
connection with a custom connection object :
+
+[source, java]
+----
+Transaction tx = BaseTransaction.getThreadTransaction();
+tx.addConnection("mydatanode", myConnection);
+----
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/orderings.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/orderings.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/orderings.adoc
new file mode 100644
index 0000000..6b9b57a
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/orderings.adoc
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Orderings
+
+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:
+
+[source, java]
+----
+Ordering o = new Ordering(Painting.NAME_PROPERTY, SortOrder.ASCENDING);
+----
+
+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:
+
+[source, java]
+----
+Ordering o = new Ordering(Painting.NAME_PROPERTY, 
SortOrder.ASCENDING_INSENSITIVE);
+List<Painting> list = ...
+o.orderList(list);
+----
+
+Note that unlike filtering with Expressions, ordering is performed in-place. 
This list object is reordered and no new list is created.
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
new file mode 100644
index 0000000..0fe969a
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
@@ -0,0 +1,803 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Queries
+
+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.
+
+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.
+
+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.
+
+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.
+[[select]]
+==== ObjectSelect
+
+===== Selecting objects
+
+ObjectSelect supersedes older SelectQuery. SelectQuery is still available and 
supported.
+
+ObjectSelect is the most commonly used query in Cayenne applications. This may 
be the only query you will ever need. It returns a list of persistent objects 
(or data rows) of a certain type specified in the query:
+
+[source, java]
+----
+List<Artist> objects = ObjectSelect.query(Artist.class).select(context);
+----
+
+This returned all rows in the "ARTIST" table. If the logs were turned on, you 
might see the following SQL printed:
+
+----
+INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
+INFO: === returned 5 row. - took 5 ms.
+----
+
+This SQL was generated by Cayenne from the ObjectSelect above. ObjectSelect 
can have a qualifier to select only the data matching specific criteria. 
Qualifier is simply an Expression (Expressions where discussed in the previous 
chapter), appended to the query using "where" method. If you only want artists 
whose name begins with 'Pablo', you might use the following qualifier 
expression:
+
+[source, java]
+----
+List<Artist> objects = ObjectSelect.query(Artist.class)
+    .where(Artist.NAME.like("Pablo%"))
+    .select(context);
+----
+
+The SQL will look different this time:
+
+----
+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.
+----
+
+ObjectSelect allows to assemble qualifier from parts, using "and" and "or" 
method to chain then together:
+
+[source, java]
+----
+List<Artist> objects = ObjectSelect.query(Artist.class)
+    .where(Artist.NAME.like("A%"))
+    .and(Artist.DATE_OF_BIRTH.gt(someDate)
+    .select(context);
+----
+
+To order the results of ObjectSelect, one or more orderings can be applied:
+
+[source, java]
+----
+List<Artist> objects = ObjectSelect.query(Artist.class)
+    .orderBy(Artist.DATE_OF_BIRTH.desc())
+    .orderBy(Artist.NAME.asc())
+    .select(context);
+----
+
+There's a number of other useful methods in ObjectSelect 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 
ObjectSelect features.
+
+===== Selecting individual columns
+
+`ObjectSelect` query can be used to fetch individual properties of objects via 
type-safe API:
+
+[source, java]
+----
+List<String> names = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME)
+    .select(context);
+----
+
+And here is example of selecting several properties, note that result will be 
`Object[]`:
+
+[source, java]
+----
+List<Object[]> nameAndDate = ObjectSelect
+    .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.DATE_OF_BIRTH)
+    .select(context);
+----
+
+===== Selecting using aggregate functions
+
+ObjectSelect query supports usage of aggregate functions. Most common variant 
of aggregation is selecting count of records, this can be done really easy:
+
+[source, java]
+----
+long count = ObjectSelect.query(Artist.class).selectCount(context);
+----
+
+But you can use aggregates in more cases, even combine selecting individual 
properties and aggregates:
+
+[source, java]
+----
+// this is artificial property signaling that we want to get full object
+Property<Artist> artistProperty = Property.createSelf(Artist.class);
+
+List<Object[]> artistAndPaintingCount = ObjectSelect.columnQuery(Artist.class, 
artistProperty, Artist.PAINTING_ARRAY.count())
+    .where(Artist.ARTIST_NAME.like("a%"))
+    .having(Artist.PAINTING_ARRAY.count().lt(5L))
+    .orderBy(Artist.PAINTING_ARRAY.count().desc(), Artist.ARTIST_NAME.asc())
+    .select(context);
+
+for(Object[] next : artistAndPaintingCount) {
+    Artist artist = (Artist)next[0];
+    long paintings = (Long)next[1];
+    System.out.println(artist.getArtistName() + " have " + paintings + " 
paintings");
+}
+----
+
+Here is generated `SQL` for this query:
+
+[source, SQL]
+----
+SELECT DISTINCT t0.ARTIST_NAME, t0.DATE_OF_BIRTH, t0.ARTIST_ID, 
COUNT(t1.PAINTING_ID)
+FROM ARTIST t0 JOIN PAINTING t1 ON (t0.ARTIST_ID = t1.ARTIST_ID)
+WHERE t0.ARTIST_NAME LIKE ?
+GROUP BY t0.ARTIST_NAME, t0.ARTIST_ID, t0.DATE_OF_BIRTH
+HAVING COUNT(t1.PAINTING_ID) < ?
+ORDER BY COUNT(t1.PAINTING_ID) DESC, t0.ARTIST_NAME
+----
+
+[[ejbql]]
+==== EJBQLQuery
+
+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):
+
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a FROM Artist a");
+----
+
+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.
+
+Although most frequently EJBQLQuery is used as an alternative to SelectQuery, 
there are also DELETE and UPDATE varieties available.
+
+NOTE: 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.
+
+
+[source, java]
+----
+EJBQLQuery select = new EJBQLQuery("select a FROM Artist a WHERE a.name = 
'Salvador Dali'");
+List<Artist> artists = context.performQuery(select);
+----
+
+[source, java]
+----
+EJBQLQuery delete = new EJBQLQuery("delete from Painting");
+context.performGenericQuery(delete);
+----
+
+[source, java]
+----
+EJBQLQuery update = new EJBQLQuery("UPDATE Painting AS p SET p.name = 'P2' 
WHERE p.name = 'P1'");
+context.performGenericQuery(update);
+----
+
+
+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:
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a, COUNT(p) FROM Artist a JOIN 
a.paintings p GROUP BY a");
+List<Object[]> result = context.performQuery(query);
+for(Object[] artistWithCount : result) {
+    Artist a = (Artist) artistWithCount[0];
+    int hasPaintings = (Integer) artistWithCount[1];
+}
+----
+
+
+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:
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a.name FROM Artist a");
+List<String> names = context.performQuery(query);
+----
+
+EJBQLQuery supports an "IN" clause with three different usage-patterns. The 
following example would require three individual positional parameters (named 
parameters could also have been used) to be supplied.
+
+[source, SQL]
+----
+select p from Painting p where p.paintingTitle in (?1,?2,?3)
+----
+
+The following example requires a single positional parameter to be supplied. 
The parameter can be any concrete implementation of the java.util.Collection 
interface such as java.util.List or java.util.Set.
+
+[source, SQL]
+----
+select p from Painting p where p.paintingTitle in ?1
+----
+
+The following example is functionally identical to the one prior.
+
+[source, SQL]
+----
+select p from Painting p where p.paintingTitle in (?1)
+----
+
+It is xref:evaluete[possible to convert] an xref:expressions[Expression] 
object used with a xref:select[SelectQuery] to EJBQL. Use the 
Expression#appendAsEJBQL methods for this purpose.
+
+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:
+
+- 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 
<> NULL"), which will evaluate differently.
+
+- 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".
+
+===== SelectById
+
+This query allows to search objects by their ID. It's introduced in Cayenne 
4.0 and uses new "fluent" API same as `ObjectSelect` query.
+
+Here is example of how to use it:
+
+[source, java]
+----
+Artist artistWithId1 = SelectById.query(Artist.class, 1)
+    .prefetch(Artist.PAINTING_ARRAY.joint())
+    .localCache()
+    .selectOne(context);
+----
+
+===== SQLSelect and SQLExec
+
+`SQLSelect` and `SQLExec` are essentially a "fluent" versions of older 
`SQLTemplate` query. `SQLSelect` can be used (as name suggests) to select 
custom data in form of entities, separate columns or collection of `DataRow. 
SQLExec` is designed to just execute any raw SQL code (e.g. updates, deletes, 
DDLs, etc.) This queries support all directives described in 
xref:sqltemplate[SQLTemplate] section.
+
+Here is example of how to use SQLSelect:
+
+[source, java]
+----
+SQLSelect<Painting> q1 = SQLSelect
+    .query(Painting.class, "SELECT * FROM PAINTING WHERE PAINTING_TITLE LIKE 
#bind($title)")
+    .params("title", "painting%")
+    .upperColumnNames()
+    .localCache()
+    .limit(100)
+    .select(context);
+----
+
+
+And here is example of how to use `SQLExec`:
+
+[source, java]
+----
+int inserted = SQLExec
+    .query("INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME) VALUES (#bind($id), 
#bind($name))")
+    .paramsArray(55, "Picasso")
+    .update(context);
+----
+
+===== MappedSelect and MappedExec
+
+`MappedSelect` and `MappedExec` is a queries that are just a reference to 
another queries stored in the DataMap. The actual stored query can be 
SelectQuery, SQLTemplate, EJBQLQuery, etc. Difference between `MappedSelect` 
and `MappedExec` is (as reflected in their names) whether underlying query 
intended to select data or just to perform some generic SQL code.
+
+NOTE: These queries are "fluent" versions of deprecated `NamedQuery` class.
+
+Here is example of how to use `MappedSelect`:
+
+[source, java]
+----
+List<Artist> results = MappedSelect.query("artistsByName", Artist.class)

+    .param("name", "Picasso")

+    .select(context);
+----
+
+And here is example of `MappedExec`:
+
+[source, java]
+----
+QueryResult result = MappedExec.query("updateQuery")

+    .param("var", "value")

+    .execute(context);
+System.out.println("Rows updated: " + result.firstUpdateCount());
+----
+
+==== ProcedureCall
+
+Stored procedures are mapped as separate objects in CayenneModeler. 
`ProcedureCall` provides a way to execute them with a certain set of 
parameters. This query is a "fluent" version of older `ProcedureQuery`. Just 
like with `SQLTemplate`, the outcome of a procedure can be anything - a single 
result set, multiple result sets, some data modification (returned as an update 
count), or a combination of these. So use root class to get a single result 
set, and use only procedure name for anything else:
+
+
+[source, java]
+----
+List<Artist> result = ProcedureCall.query("my_procedure", Artist.class)
+    .param("p1", "abc")
+    .param("p2", 3000)
+    .call(context)
+    .firstList();
+----
+
+[source, java]
+----
+// here we do not bother with root class.
+// Procedure name gives us needed routing information
+ProcedureResult result = ProcedureCall.query("my_procedure")
+    .param("p1", "abc")
+    .param("p2", 3000)
+    .call();
+----
+
+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. For 
stored procedures declaref any OUT or INOUT parameters, `ProcedureResult` have 
convenient utility method to get them:
+
+[source, java]
+----
+ProcedureResult result = ProcedureCall.query("my_procedure")
+    .call(context);
+
+// read OUT parameters
+Object out = result.getOutParam("out_param");
+----
+
+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.
+
+==== Custom Queries
+
+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 
`org.apache.cayenne.query.Query` interface. The easiest way to go about it is 
to subclass some of the base queries in Cayenne.
+
+E.g. to do something directly in the JDBC layer, you might subclass 
AbstractQuery:
+
+[source, 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
+            }
+        };
+    }
+}
+----
+
+To delegate the actual query execution to a standard Cayenne query, you may 
subclass IndirectQuery:
+
+
+[source, 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
+    }
+}
+----
+
+In fact many internal Cayenne queries are IndirectQueries, delegating to 
SelectQuery or SQLTemplate after some preprocessing.
+
+[[sqltemplate]]
+==== SQLTemplate
+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:
+
+
+[source, java]
+----
+SQLTemplate select = new SQLTemplate(Artist.class, "select * from ARTIST");
+List<Artist> result = context.performQuery(select);
+----
+
+[source, java]
+----
+SQLTemplate update = new SQLTemplate(Artist.class, "delete from ARTIST");
+QueryResponse response = context.performGenericQuery(update);
+----
+
+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".
+
+NOTE: 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.
+
+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.
+
+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:
+
+[source, 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);
+----
+
+===== Scripting SQLTemplate with Velocity
+
+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.
+
+Check Velocity docs for the syntax details. Here we'll just mention the two 
main scripting elements - "variables" (that look like `$var`) and "directives" 
(that look like `#directive(p1 p2 p3)`). 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.
+
+
+===== Variable Substitution
+
+All variables in the template string are replaced from query parameters:
+
+
+[source, 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"
+----
+
+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 (`Artist.class` in this case) , as we are not 
planning on converting the result to objects.
+
+Variable substitution within the text uses `"object.toString()"` 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 `#bind` directive as described below.
+
+[[directives]]
+===== Directives
+
+These are the Cayenne directives used to customize SQLTemplate parsing and 
integrate it with the JDBC layer:
+
+====== #bind
+
+Creates a PreparedStatement positional parameter in place of the directive, 
binding the value to it before statement execution. `#bind` 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.
+
+Semantics:
+
+[source]
+----
+#bind(value)
+#bind(value jdbcType)
+#bind(value jdbcType scale)
+----
+
+Arguments:
+
+- `value` - 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.
+
+- `jdbcType` - is a JDBC data type of the parameter as defined in 
`java.sql.Types`.
+
+- `scale` - An optional scale of the numeric value. Same as "scale" in 
PreparedStatement.
+
+Usage:
+
+[source]
+----
+#bind($xyz)
+#bind('str')
+#bind($xyz 'VARCHAR')
+#bind($xyz 'DECIMAL' 2)
+----
+
+Full example:
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID = #bind($id)
+----
+
+
+====== #bindEqual
+
+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 `"ID = 
#bind(..)"` with `"ID #bindEqual(..)"`. 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, `"= ?"` is generated, 
but if it is, the resulting chunk of the SQL would look like `"IS NULL"` and 
will be compilant with what the DB expects.
+
+Semantics:
+
+
+[source]
+----
+#bindEqual(value)
+#bindEqual(value jdbcType)
+#bindEqual(value jdbcType scale)
+----
+
+Arguments: (same as #bind)
+
+Usage:
+
+[source]
+----
+#bindEqual($xyz)
+#bindEqual('str')
+#bindEqual($xyz 'VARCHAR')
+#bindEqual($xyz 'DECIMAL' 2)
+----
+
+
+Full example:
+
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID #bindEqual($id)
+----
+
+====== #bindNotEqual
+
+This directive deals with the same issue as `#bindEqual` above, only it 
generates "not equal" in front of the value (or IS NOT NULL).
+
+Semantics:
+
+[source]
+----
+#bindNotEqual(value)
+#bindNotEqual(value jdbcType)
+#bindNotEqual(value jdbcType scale)
+----
+
+Arguments: (same as #bind)
+
+Usage:
+
+[source]
+----
+#bindNotEqual($xyz)
+#bindNotEqual('str')
+#bindNotEqual($xyz 'VARCHAR')
+#bindNotEqual($xyz 'DECIMAL' 2)
+----
+
+Full example:
+
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID #bindEqual($id)
+----
+
+====== #bindObjectEqual
+
+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.
+
+Semantics:
+
+[source]
+----
+#bindObjectEqual(value columns idColumns)
+----
+
+Arguments:
+
+- `value` - must be a variable that is resolved from the query parameters to a 
Persistent or ObjectId.
+
+- `columns` - the names of the columns to generate in the SQL.
+
+- `idColumn` - the names of the ID columns for a given entity. Must match the 
order of "columns" to match against.
+
+Usage:
+
+[source]
+----
+#bindObjectEqual($a 't0.ID' 'ID')
+#bindObjectEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])
+----
+
+Full example:
+
+[source, 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));
+----
+
+====== #bindObjectNotEqual
+
+Same as #bindObjectEqual above, only generates "not equal" operator for value 
comparison (or IS NOT NULL).
+
+Semantics:
+
+[source]
+----
+#bindObjectNotEqual(value columns idColumns)
+----
+
+Arguments: (same as #bindObjectEqual)
+
+Usage:
+
+[source]
+----
+#bindObjectNotEqual($a 't0.ID' 'ID')
+#bindObjectNotEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])
+----
+
+Full example:
+
+[source, 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));
+----
+
+====== #result
+
+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.
+
+Semantics:
+
+[source]
+----
+#result(column)
+#result(column javaType)
+#result(column javaType alias)
+#result(column javaType alias dataRowKey)
+----
+
+Arguments:
+
+- `column` - the name of the column to render in SQL SELECT clause.
+
+- `javaType` - 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 "_#result('A' 'String')_", "_#result('B' 
'java.lang.String')_" and "_#result('C' 'int')_" are all valid
+
+- `alias` - specifies both the SQL alias of the column and the value key in 
the DataRow. If omitted, "column" value is used.
+
+- `dataRowKey` - 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.
+
+Usage:
+
+[source]
+----
+#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')
+----
+
+Full example:
+
+
+[source, SQL]
+----
+SELECT #result('ID' 'int'), #result('NAME' 'String'), #result('DATE_OF_BIRTH' 
'java.util.Date') FROM ARTIST
+----
+
+====== Note
+
+For advanced features you may look at the xref:velocity[Apache Velocity 
extension]
+
+====== Mapping SQLTemplate Results
+
+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.
+
+By default SQLTemplate is expected to return a List of Persistent objects of 
its root type. This is the simple case:
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
+
+// List of Artists
+List<Artist> artists = context.performQuery(query);
+----
+
+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:
+
+[source, 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<DataRow> rows = context.performQuery(query);
+----
+
+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.
+
+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:
+
+[source, 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<BigDecimal> prices = context.performQuery(query);
+----
+
+[source, 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<Object[]> data = context.performQuery(query);
+----
+
+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:
+
+[source, 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<Artist> objects = context.performQuery(query);
+----
+
+And the final tip deals with capitalization of the DataRow keys. Queries like 
`"SELECT * FROM..."` and even `"SELECT COLUMN1, COLUMN2, ... FROM ..."` can 
sometimes result in Cayenne exceptions on attempts to convert fetched DataRows 
to objects. Essentially any query that is not using a `#result` directive to 
describe the result set is prone to this problem, as different databases may 
produce different capitalization of the java.sql.ResultSet columns.
+
+The most universal way to address this issue is to describe each column 
explicitly in the SQLTemplate via `#result`, e.g.: `"SELECT #result('column1'), 
#result('column2'), .."`. 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):
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
+query.setColumnNamesCapitalization(CapsStrategy.LOWER);
+List objects = context.performQuery(query);
+----
+
+or
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
+query.setColumnNamesCapitalization(CapsStrategy.UPPER);
+List objects = context.performQuery(query);
+----
+
+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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
new file mode 100644
index 0000000..b556536
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Starting Cayenne
+
+==== Starting and Stopping ServerRuntime
+
+In runtime Cayenne is accessed via 
`org.apache.cayenne.configuration.server.ServerRuntime`. ServerRuntime is 
created by calling a convenient builder:
+
+[source, java]
+----
+ServerRuntime runtime = ServerRuntime.builder()
+                .addConfig("com/example/cayenne-project.xml")
+                .build();
+----
+
+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).
+
+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 
xref:customize["Customizing Cayenne Runtime"] chapter. Here we'll just show an 
example of how an application might turn on external transactions:
+
+[source, java]
+----
+Module extensions = binder ->
+                
ServerModule.contributeProperties(binder).put(Constants.SERVER_EXTERNAL_TX_PROPERTY,
 "true");
+ServerRuntime runtime = ServerRuntime.builder()
+                .addConfig("com/example/cayenne-project.xml")
+                .addModule(extensions)
+                .build();
+----
+
+It is a good idea to shut down the runtime when it is no longer needed, 
usually before the application itself is shutdown:
+
+[source, java]
+----
+runtime.shutdown();
+----
+
+
+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.
+
+==== Merging Multiple Projects
+
+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 independently 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 builder:
+
+[source, java]
+----
+ServerRuntime runtime = ServerRuntime.builder()
+        .addConfig("com/example/cayenne-project.xml")
+        .addConfig("org/foo/cayenne-library1.xml")
+        .addConfig("org/foo/cayenne-library2.xml")
+        .build();
+----
+
+When the projects are merged, the following rules are applied:
+
+
+- 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.
+
+- Runtime DataDomain name is set to the name of the last project in the list.
+
+- 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.
+
+- 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.
+
+- If there are two or more DataNodes with the same name, only one DataNodes 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.
+
+- 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 
`DataDomainProvider.createAndInitDataDomain()`.
+
+==== Web Applications
+
+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.
+
+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:
+
+[source, XML]
+----
+<web-app>
+    ...
+    <filter>
+        <filter-name>cayenne-project</filter-name>
+        
<filter-class>org.apache.cayenne.configuration.web.CayenneFilter</filter-class>
+    </filter>
+     <filter-mapping>
+        <filter-name>cayenne-project</filter-name>
+        <url-pattern>/*</url-pattern>
+     </filter-mapping>
+    ...
+ </web-app>
+----
+
+
+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.
+
+When the application runs, all HTTP requests matching the filter url-pattern 
will have access to a session-scoped ObjectContext like this:
+
+[source, java]
+----
+ ObjectContext context = BaseContext.getThreadObjectContext();
+----
+
+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.
+
+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 `org.apache.cayenne.configuration.web.WebModule` 
module that provides `org.apache.cayenne.configuration.web.RequestHandler` 
service. This is the service to override in the custom modules if you need to 
provide a different ObjectContext scope, etc.
+
+
+NOTE: 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.
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
new file mode 100644
index 0000000..aa90e0e
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
@@ -0,0 +1,354 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Performance Tuning
+
+==== Prefetching
+
+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.
+
+Prefetching example:
+
+[source, Java]
+----
+ObjectSelect<Artist> query = ObjectSelect.query(Artist.class);
+
+// instructs Cayenne to prefetch one of Artist's relationships
+query.prefetch(Artist.PAINTINGS.disjoint());
+
+// the above line is equivalent to the following:
+// query.prefetch("paintings", PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
+
+// query is expecuted as usual, but the resulting Artists will have
+// their paintings "inflated"
+List<Artist> artists = query.select(context);
+----
+
+All types of relationships can be preftetched - to-one, to-many, flattened. A 
prefetch can span multiple relationships:
+
+[source, Java]
+----
+query.prefetch(Artist.PAINTINGS.dot(Painting.GALLERY).disjoint());
+----
+
+A query can have multiple prefetches:
+
+[source, Java]
+----
+query.prefetch(Artist.PAINTINGS.disjoint());
+query.prefetch(Artist.PAINTINGS.dot(Painting.GALLERY).disjoint());
+----
+
+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).
+
+===== Prefetching Semantics
+
+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 
`org.apache.cayenne.query.PrefetchTreeNode`:
+
+[source]
+----
+PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS
+PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS
+PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS
+----
+
+There's no limitation on mixing different types of semantics in the same 
query. Each prefetch can have its own semantics. `SelectQuery` uses 
`DISJOINT_PREFETCH_SEMANTICS` by default. `ObjectSelect` requires explicit 
semantics as we've seen above. `SQLTemplate_ and _ProcedureQuery` are both 
using `JOINT_PREFETCH_SEMANTICS` and it can not be changed due to the nature of 
those two queries.
+
+===== Disjoint Prefetching Semantics
+
+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.
+
+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.
+
+===== Disjoint-by-ID Prefetching Semantics
+
+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).
+
+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 *the only type of prefetch* that can handle SelectQueries with *fetch* 
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.
+
+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.
+
+===== Joint Prefetching Semantics
+
+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.
+
+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.
+
+===== Similar Behaviours Using EJBQL
+
+It is possible to achieve similar behaviours with xref:ejbql[EJBQLQuery] 
queries by employing the "FETCH" keyword.
+
+[source, SQL]
+----
+SELECT a FROM Artist a LEFT JOIN FETCH a.paintings
+----
+
+In this case, the Paintings that exist for the Artist will be obtained at the 
same time as the Artists are fetched. Refer to third-party query language 
documentation for further detail on this mechanism.
+
+==== Data Rows
+
+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.
+
+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.:
+
+[source, Java]
+----
+ObjectSelect<DataRow> query = ObjectSelect.dataRowQuery(Artist.class);
+
+List<DataRow> rows = query.select(context);
+----
+
+[source, Java]
+----
+SQLSelect<DataRow> query = SQLSelect.dataRowQuery("SELECT * FROM ARTIST");
+List<DataRow> rows = query.select(context);
+----
+
+Individual DataRows may be converted to Persistent objects as needed. So e.g. 
you may implement some in-memory filtering, only converting a subset of fetched 
objects:
+
+
+[source, 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...
+        ...
+    }
+}
+----
+
+==== Specific Attributes and Relationships with EJBQL
+
+It is possible to fetch specific attributes and relationships from a model 
using xref:ejbqlquery[EJBQLQuery]. The following example would return a 
java.util.List of String objects;
+
+[source, SQL]
+----
+SELECT a.name FROM Artist a
+----
+
+The following will yield a java.util.List containing Object[] instances, each 
of which would contain the name followed by the dateOfBirth value.
+
+[source, SQL]
+----
+SELECT a.name, a.dateOfBirth FROM Artist a
+----
+
+Refer to third-party query language documentation for further detail on this 
mechanism.
+
+==== Iterated Queries
+
+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.
+
+Iterated query is not actually a special query. Any selecting query can be 
executed in iterated mode by an ObjectContext. ObjectContext creates an object 
called `ResultIterator` that is backed by an open ResultSet. Iterator 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.
+
+Data is read from ResultIterator one row/object at a time until it is 
exhausted. There are two styles of accessing ResultIterator - direct access 
which requires explicit closing to avoid JDBC resources leak, or a callback 
that lets Cayenne handle resource management. In both cases iteration can be 
performed using "for" loop, as ResultIterator is "Iterable".
+
+Direct access. Here common sense tells us that ResultIterators instances 
should be processed and closed as soon as possible to release the DB 
connection. E.g. storing open iterators between HTTP requests for unpredictable 
length of time would quickly exhaust the connection pool.
+
+[source, Java]
+----
+try(ResultIterator<Artist> it = 
ObjectSelect.query(Artist.class).iterator(context)) {
+    for(Artist a : it) {
+       // do something with the object...
+       ...
+    }
+}
+----
+
+Same thing with a callback:
+
+[source, Java]
+----
+ObjectSelect.query(Artist.class).iterate(context, (Artist a) -> {
+    // do something with the object...
+    ...
+});
+----
+
+Another example is a batch iterator that allows to process more than one 
object in each iteration. This is a common scenario in various data processing 
jobs - read a batch of objects, process them, commit the results, and then 
repeat. This allows to further optimize processing (e.g. by avoiding frequent 
commits).
+
+[source, Java]
+----
+try(ResultBatchIterator<Artist> it = 
ObjectSelect.query(Artist.class).batchIterator(context, 100)) {
+    for(List<Artist> list : it) {
+       // do something with each list
+       ...
+       // possibly commit your changes
+       context.commitChanges();
+    }
+}
+----
+
+==== Paginated Queries
+
+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:
+
+[source, Java]
+----
+// the fact that result is paginated is transparent
+List<Artist> artists =
+    ObjectSelect.query(Artist.class).pageSize(50).select(context);
+----
+
+Having said that, DataRows option can be combined with pagination, providing 
the best of both worlds:
+
+
+[source, Java]
+----
+List<DataRow> rows =
+    ObjectSelect.dataRowQuery(Artist.class).pageSize(50).select(context);
+----
+
+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.
+
+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.
+
+[[caching]]
+==== Caching and Fresh Data
+
+===== Object Caching
+
+===== Query Result Caching
+
+Cayenne supports mostly transparent caching of the query results. There are 
two levels of the cache: local (i.e. results cached by the ObjectContext) and 
shared (i.e. the results cached at the stack level and shared between all 
contexts). Local cache is much faster then the shared one, but is limited to a 
single context. It is often used with a shared read-only ObjectContext.
+
+To take advantage of query result caching, the first step is to mark your 
queries appropriately. Here is an example for ObjectSelect query. Other types 
of queries have similar API:
+
+[source, Java]
+----
+ObjectSelect.query(Artist.class).localCache("artists");
+----
+
+This tells Cayenne that the query created here would like to use local cache 
of the context it is executed against. A vararg parameter to `localCache()` (or 
`sharedCache()`) method contains so called "cache groups". Those are arbitrary 
names that allow to categorize queries for the purpose of setting cache 
policies or explicit invalidation of the cache. More on that below.
+
+The above API is enough for the caching to work, but by default your cache is 
an unmanaged LRU map. You can't control its size, expiration policies, etc. For 
the managed cache, you will need to explicitly use one of the more advanced 
cache providers. One such provider available in Cayenne is a provider for 
http://www.ehcache.org[EhCache]. It can be enabled on ServerRuntime startup in 
a custom Module:
+
+[source, Java]
+----
+ServerRuntimeBuilder
+  .builder()
+  .addModule((binder) ->
+     binder.bind(QueryCache.class).to(EhCacheQueryCache.class)
+  )
+  .build();
+----
+
+By default EhCache reads a file called "ehcache.xml" located on classpath. You 
can put your cache configuration in that file. E.g.:
+
+[source, XML]
+----
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"
+       monitoring="off" dynamicConfig="false">
+
+       <defaultCache maxEntriesLocalHeap="1000" eternal="false"
+               overflowToDisk="false" timeToIdleSeconds="3600" 
timeToLiveSeconds="3600">
+       </defaultCache>
+
+       <cache name="artists" timeToLiveSeconds="20" maxEntriesLocalHeap="100" 
/>
+</ehcache>
+----
+
+The example shows how to configure default cache settings ("defaultCache") as 
well as settings for a named cache group ("artists"). For many other things you 
can put in "ehcache.xml" refer to EhCache docs.
+
+Often "passive" cache expiration policies similar to shown above are not 
sufficient, and the users want real-time cache invalidation when the data 
changes. So in addition to those policies, the app can invalidate individual 
cache groups explicitly with `RefreshQuery`:
+
+[source, Java]
+----
+RefreshQuery refresh = new RefreshQuery("artist");
+context.performGenericQuery(refresh);
+----
+
+The above can be used e.g. to build UI for manual cache invalidation. It is 
also possible to automate cache refresh when certain entities are committed. 
This requires including `cayenne-lifecycle.jar` deoendency. From that library 
you will need two things: `@CacheGroups` annotation to mark entities that 
generate cache invalidation events and  `CacheInvalidationFilter` that catches 
the updates to the annotated objects and generates appropriate invalidation 
events:
+
+[source, Java]
+----
+// configure filter on startup
+ServerRuntimeBuilder
+  .builder()
+  .addModule((binder) ->
+     
binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST).add(CacheInvalidationFilter.class)
+  )
+  .build();
+----
+
+
+Now you can associate entities with cache groups, so that commits to those 
entities would atomatically invalidate the groups:
+
+[source, Java]
+----
+@CacheGroups("artists")
+public class Artist extends _Artist {
+}
+----
+
+Finally you may cluster cache group events. They are very small and can be 
efficiently sent over the wire to other JVMs running Cayenne. An example of 
Cayenne setup with event clustering is 
https://github.com/andrus/wowodc13/tree/master/services/src/main/java/demo/services/cayenne[available
 on GitHub].
+
+
+==== Turning off Synchronization of ObjectContexts
+
+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:
+
+- 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.
+
+- 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.
+
+- 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.
+
+- Some contexts may not want to be refreshed. A refresh in the middle of an 
operation may lead to unpredictable results.
+
+- Synchronization will interfere with optimistic locking.
+
+So we've made a good case for disabling synchronization in most webapps. To do 
that, set to "false" the following DI property - 
`Constants.SERVER_CONTEXTS_SYNC_PROPERTY`, using one of the standard Cayenne DI 
approaches. E.g. from command line:
+
+----
+$ java -Dcayenne.server.contexts_sync_strategy=false
+----
+
+Or by changing the standard properties Map in a custom extensions module:
+
+[source, Java]
+----
+public class MyModule implements Module {
+
+    @Override
+    public void configure(Binder binder) {
+        
binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_CONTEXTS_SYNC_PROPERTY,
 "false");
+    }
+}
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
new file mode 100644
index 0000000..5e211d1
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+== Cayenne Framework - Remote Object Persistence
+
+include::part3/rop.adoc[]
+
+include::part3/ropSetup.adoc[]
+
+include::part3/serverImpl.adoc[]
+
+include::part3/clientImpl.adoc[]
+
+include::part3/ropDeployment.adoc[]
+
+include::part3/limitations.adoc[]
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
new file mode 100644
index 0000000..027a22e
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
@@ -0,0 +1,16 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Implementing ROP Client
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
----------------------------------------------------------------------
diff --git 
a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
new file mode 100644
index 0000000..f378cdb
--- /dev/null
+++ 
b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
@@ -0,0 +1,18 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to you under the Apache License, Version
+// 2.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+
+=== Current Limitations
+
+
+

Reply via email to