http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/performance-tuning.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/performance-tuning.xml b/docs/docbook/cayenne-guide/src/docbkx/performance-tuning.xml deleted file mode 100644 index 2b569dd..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/performance-tuning.xml +++ /dev/null @@ -1,379 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> -<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" - version="5.0" xml:id="performance-tuning"> - <title>Performance Tuning</title> - <section xml:id="prefetching"> - <title>Prefetching</title> - <para>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.</para> - <para>Prefetching example: - <programlisting language="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);</programlisting>All - types of relationships can be preftetched - to-one, to-many, flattened. A prefetch can - span multiple relationships: - <programlisting language="java">query.prefetch(Artist.PAINTINGS.dot(Painting.GALLERY).disjoint());</programlisting></para> - <para>A query can have multiple - prefetches:<programlisting language="java">query.prefetch(Artist.PAINTINGS.disjoint()); -query.prefetch(Artist.PAINTINGS.dot(Painting.GALLERY).disjoint());</programlisting></para> - <para>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).</para> - - <section xml:id="prefetching-semantics"> - <title>Prefetching Semantics</title> - <para>Prefetching semantics defines a strategy to prefetch relationships. Depending on - it, Cayenne would generate different types of queries. The end result is the same - - query root objects with related objects fully resolved. However semantics can affect - preformance, in some cases significantly. There are 3 types of prefetch semantics, - all defined as constants in - <code>org.apache.cayenne.query.PrefetchTreeNode</code>:<programlisting language="java">PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS -PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS -PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS</programlisting></para> - <para>There's no limitation on mixing different types of semantics in the same query. - Each prefetch can have its own semantics. <code>SelectQuery</code> uses - <code>DISJOINT_PREFETCH_SEMANTICS</code> by default. <code>ObjectSelect</code> - requires explicit semantics as we've seen above. <code>SQLTemplate</code> and - <code>ProcedureQuery</code> are both using <code>JOINT_PREFETCH_SEMANTICS</code> - and it can not be changed due to the nature of those two queries.</para> - </section> - <section xml:id="disjoint-prefetch-semantics"> - <title>Disjoint Prefetching Semantics</title> - <para>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. </para> - <para>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.</para> - - </section> - <section xml:id="disjoint-by-id-prefetch-semantics"> - <title>Disjoint-by-ID Prefetching Semantics</title> - <para>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).</para> - <para>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 - <emphasis role="bold">the only type of prefetch</emphasis> that can handle - SelectQueries with <emphasis role="bold">fetch limit</emphasis>. Both joint and - regular disjoint prefetches may produce invalid results or generate inefficient - fetch-the-entire table SQL when fetch limit is in effect. </para> - <para>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.</para> - </section> - <section xml:id="joint-prefetch-semantics"> - <title>Joint Prefetching Semantics</title> - <para>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.</para> - <para>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.</para> - </section> - <section xml:id="prefetching-with-ejbql"> - <title>Similar Behaviours Using EJBQL</title> - <para>It is possible to achieve similar behaviours with - <link linkend="ejbqlquery">EJBQLQuery</link> queries by employing the "FETCH" - keyword.</para> - - <programlisting language="sql">SELECT a FROM Artist a LEFT JOIN FETCH a.paintings</programlisting> - - <para> - 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. - </para> - - </section> - - </section> - <section xml:id="datarows"> - <title>Data Rows</title> - <para>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. </para> - <para>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.:<programlisting language="java">ObjectSelect<DataRow> query = ObjectSelect.dataRowQuery(Artist.class); - -List<DataRow> rows = query.select(context);</programlisting><programlisting language="java">SQLSelect<DataRow> query = SQLSelect.dataRowQuery("SELECT * FROM ARTIST"); -List<DataRow> rows = query.select(context);</programlisting></para> - <para>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:<programlisting language="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... - ... - } -}</programlisting></para> - </section> - - <section xml:id="specific-attributes-with-ejbql"> - <title>Specific Attributes and Relationships with EJBQL</title> - <para> - It is possible to fetch specific attributes and relationships from a model - using <link linkend="ejbqlquery">EJBQLQuery</link>. - The following example would return a java.util.List of String objects; - </para> - - <programlisting language="sql">SELECT a.name FROM Artist a</programlisting> - - <para>The following will yield a java.util.List containing Object[] instances, each of which - would contain the name followed by the dateOfBirth value.</para> - - <programlisting language="sql">SELECT a.name, a.dateOfBirth FROM Artist a</programlisting> - - <para>Refer to third-party query language documentation for further - detail on this mechanism.</para> - </section> - - <section xml:id="iterated-queries"> - <title>Iterated Queries</title> - <para>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. </para> - <para>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 - <code>ResultIterator</code> 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. </para> - <para>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".</para> - <para>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.<programlisting language="java">try(ResultIterator<Artist> it = ObjectSelect.query(Artist.class).iterator(context)) { - for(Artist a : it) { - // do something with the object... - ... - } -}</programlisting></para> - <para>Same thing with a - callback:<programlisting language="java">ObjectSelect.query(Artist.class).iterate(context, (Artist a) -> { - // do something with the object... - ... -});</programlisting></para> - <para>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).<programlisting language="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(); - } -}</programlisting></para> - </section> - <section xml:id="paginated-queries"> - <title>Paginated Queries</title> - <para>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:</para> - <para> - <programlisting language="java">// the fact that result is paginated is transparent -List<Artist> artists = - ObjectSelect.query(Artist.class).pageSize(50).select(context);</programlisting> - </para> - <para>Having said that, DataRows option can be combined with pagination, providing the best - of both - worlds:<programlisting language="java">List<DataRow> rows = - ObjectSelect.dataRowQuery(Artist.class).pageSize(50).select(context);</programlisting></para> - <para>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.</para> - <para>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.</para> - </section> - <section xml:id="caching-and-fresh-data"> - <title>Caching and Fresh Data</title> - <section xml:id="object-caching"> - <title>Object Caching</title> - </section> - <section xml:id="query-result-caching"> - <title>Query Result Caching</title> - <para>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. </para> - <para>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:<programlisting language="java">ObjectSelect.query(Artist.class).localCache("artists");</programlisting></para> - <para>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 <code>localCache()</code> - (or <code>sharedCache()</code>) 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.</para> - <para>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 <link - xlink:href="http://www.ehcache.org/">EhCache</link>. It can be enabled on - ServerRuntime startup in a custom - Module:<programlisting language="java">ServerRuntimeBuilder - .builder() - .addModule((binder) -> - binder.bind(QueryCache.class).to(EhCacheQueryCache.class) - ) - .build();</programlisting></para> - <para>By default EhCache reads a file called "ehcache.xml" located on classpath. You can - put your cache configuration in that file. - E.g.:<programlisting language="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></programlisting></para> - <para>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.</para> - <para>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 - <code>RefreshQuery</code>:<programlisting language="java">RefreshQuery refresh = new RefreshQuery("artist"); -context.performGenericQuery(refresh);</programlisting></para> - <para>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 <code>cayenne-lifecycle.jar</code> deoendency. From that library - you will need two things: <code>@CacheGroups</code> annotation to mark entities that - generate cache invalidation events and  <code>CacheInvalidationFilter</code> that - catches the updates to the annotated objects and generates appropriate invalidation - events:<programlisting language="java">// configure filter on startup -ServerRuntimeBuilder - .builder() - .addModule((binder) -> - binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST).add(CacheInvalidationFilter.class) - ) - .build();</programlisting></para> - <para>Now you can associate entities with cache groups, so that commits to those - entities would atomatically invalidate the - groups:<programlisting language="java">@CacheGroups("artists") -public class Artist extends _Artist { -}</programlisting></para> - <para>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 <link - xlink:href="https://github.com/andrus/wowodc13/tree/master/services/src/main/java/demo/services/cayenne" - >available on GitHub</link>.</para> - </section> - </section> - <section xml:id="turning-off-synchronization-of-objectcontexts"> - <title>Turning off Synchronization of ObjectContexts</title> - <para>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:<itemizedlist> - <listitem> - <para>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. </para> - </listitem> - <listitem> - <para>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.</para> - </listitem> - <listitem> - <para>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.</para> - </listitem> - <listitem> - <para>Some contexts may not want to be refreshed. A refresh in the middle of an - operation may lead to unpredictable results. </para> - </listitem> - <listitem> - <para>Synchronization will interfere with optimistic locking. </para> - </listitem> - </itemizedlist>So we've made a good case for disabling synchronization in most webapps. - To do that, set to "false" the following DI property - - <code>Constants.SERVER_CONTEXTS_SYNC_PROPERTY</code>, using one of the standard - Cayenne DI approaches. E.g. from command - line:<screen><prompt>$</prompt> java -Dcayenne.server.contexts_sync_strategy=false</screen>Or - by changing the standard properties Map in a custom extensions - module:<programlisting language="java">public class MyModule implements Module { - - @Override - public void configure(Binder binder) { - binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_CONTEXTS_SYNC_PROPERTY, "false"); - } -}</programlisting></para> - </section> -</chapter>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/persistent-objects-objectcontext.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/persistent-objects-objectcontext.xml b/docs/docbook/cayenne-guide/src/docbkx/persistent-objects-objectcontext.xml deleted file mode 100644 index 6305c9a..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/persistent-objects-objectcontext.xml +++ /dev/null @@ -1,288 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> -<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" - version="5.0" xml:id="persistent-objects-objectcontext"> - <title>Persistent Objects and ObjectContext</title> - <section xml:id="objectcontext"> - <title>ObjectContext</title> - <para>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:<programlisting language="java">ObjectContext context = runtime.newContext();</programlisting></para> - <para>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.</para> - <para>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).</para> - <para>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.</para> - </section> - <section xml:id="persistent-lifecycle"> - <title>Persistent Object and its Lifecycle</title> - <para>Cayenne can persist Java objects that implement <code>org.apache.cayenne.Persistent</code> - interface. Generally persistent classes are generated from the model as described above, - so users do not have to worry about superclass and property implementation details. </para> - <para>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 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.</para> - <para>Each persistent object belongs to a single ObjectContext, and can be in one of the following - persistence states (as defined in <code>org.apache.cayenne.PersistenceState</code>) - :<table frame="void"> - <caption>Persistence States</caption> - <col width="16%"/> - <col width="84%"/> - <tbody> - <tr> - <td>TRANSIENT</td> - <td>The object is not registered with an ObjectContext and will not be - persisted.</td> - </tr> - <tr> - <td>NEW</td> - <td>The object is freshly registered in an ObjectContext, but has not been - saved to the database yet and there is no matching database row.</td> - </tr> - <tr> - <td>COMMITTED</td> - <td>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.</td> - </tr> - <tr> - <td>MODIFIED</td> - <td>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.</td> - </tr> - <tr> - <td>HOLLOW</td> - <td>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.</td> - </tr> - <tr> - <td>DELETED</td> - <td>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.</td> - </tr> - </tbody> - </table></para> - </section> - <section xml:id="persistent-operations"> - <title>ObjectContext Persistence API</title> - <para>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 "<emphasis role="italic" - >performQuery</emphasis>" - method:<programlisting language="java">SelectQuery query = new SelectQuery(Artist.class); -List<Artist> artists = context.performQuery(query);</programlisting>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.</para> - <para>Some queries can be quite complex, returning multiple result sets or even updating the - database. For such queries ObjectContext provides "<emphasis role="italic" - >performGenericQuery</emphasis>"method. While not nearly as commonly-used as - "performQuery", it is nevertheless important in some situations. - E.g.:<programlisting language="java">Collection<Query> queries = ... // multiple queries that need to be run together -QueryChain query = new QueryChain(queries); - -QueryResponse response = context.performGenericQuery(query);</programlisting></para> - <para>An application might modify selected objects. E.g.:</para> - <programlisting language="java">Artist selectedArtist = artists.get(0); -selectedArtist.setName("Dali");</programlisting> - <para>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 - "<emphasis role="italic" - >commitChanges</emphasis>":<programlisting language="java">context.commitChanges();</programlisting>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. </para> - <para>If instead of commit, we wanted to reset all changed objects to the previously - committed state, we'd call <emphasis>rollbackChanges</emphasis> - instead:<programlisting language="java">context.rollbackChanges();</programlisting></para> - <para>"<emphasis role="italic">newObject</emphasis>" method call creates a persistent object - and sets its state to - "NEW":<programlisting language="java">Artist newArtist = context.newObject(Artist.class); -newArtist.setName("Picasso");</programlisting></para> - <para>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.</para> - <para><emphasis>deleteObjects</emphasis> method takes one or more Persistent objects and - marks them as - "DELETED":<programlisting language="java">context.deleteObjects(artist1); -context.deleteObjects(artist2, artist3, artist4);</programlisting>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".</para> - <para><emphasis>localObject</emphasis> returns a copy of a given persistent object that is - "local" to a given ObjectContext:</para> - <para>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:<programlisting language="java">ObjectContext editingContext = runtime.newContext(); -Artist localArtist = editingContext.localObject(artist);</programlisting></para> - <para>Often an appliction needs to inspect mapping metadata. This information is stored in - the EntityResolver object, accessible via the - ObjectContext:<programlisting language="java">EntityResolver resolver = objectContext.getEntityResolver();</programlisting></para> - <para>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 en bulk, - etc. Check the latest JavaDocs for details.</para> - </section> - <section xml:id="cayenne-helper-class"> - <title>Cayenne Helper Class</title> - <para>There is a useful helper class called "Cayenne" (fully-qualified name - <code>"org.apache.cayenne.Cayenne"</code>) that builds on ObjectContext API to - provide a number of very common operations. E.g. get a primary key (most entities do not - model PK as an object property) - :<programlisting language="java">long pk = Cayenne.longPKForObject(artist);</programlisting></para> - <para>It also provides the reverse operation - finding an object given a known - PK:<programlisting language="java">Artist artist = Cayenne.objectForPK(context, Artist.class, 34579);</programlisting></para> - <para>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:<programlisting language="java">Artist artist = (Artist) Cayenne.objectForQuery(context, new SelectQuery(Artist.class));</programlisting></para> - <para>Feel free to explore Cayenne class API for other useful methods.</para> - </section> - <section xml:id="objectcontext-nesting"> - <title>ObjectContext Nesting</title> - <para>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. </para> - <para>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.</para> - <para>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. </para> - <para>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.</para> - <para>To create a nested context, use an instance of ServerRuntime, passing it the desired - parent:<programlisting language="java">ObjectContext parent = runtime.newContext(); -ObjectContext nested = runtime.newContext((DataChannel) parent);</programlisting>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:<programlisting language="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();</programlisting><programlisting language="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();</programlisting></para> - </section> - <section xml:id="generic-persistent-objects"> - <title>Generic Persistent Objects</title> - <para>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.</para> - <para>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.</para> - <para>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:<programlisting language="java">DataObject generic = ((DataContext) context).newObject("GenericEntity");</programlisting><programlisting language="java">DataObject generic = new CayenneDataObject(); -generic.setObjectId(new ObjectId("GenericEntity")); -context.registerNewObject(generic);</programlisting>SelectQuery - for generic object should be created passing entity name String in constructor, instead - of a Java - class:<programlisting language="java">SelectQuery query = new SelectQuery("GenericEntity");</programlisting>Use - DataObject API to access and modify properties of a generic - object:<programlisting language="java">String name = (String) generic.readProperty("name"); -generic.writeProperty("name", "New Name");</programlisting>This - is how an application can obtain entity name of a generic - object:<programlisting language="java">String entityName = generic.getObjectId().getEntityName();</programlisting></para> - </section> - <section xml:id="transactions"> - <title>Transactions</title> - <para>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.</para> - <para>Two cases where transactions need to be taken into consideration are container-managed - and application-managed transactions. </para> - <para>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 <code>Constants.SERVER_EXTERNAL_TX_PROPERTY</code> - (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.</para> - <para>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 - <code>ServerRuntime.performInTransaction</code> - method:<programlisting language="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; -});</programlisting></para> - <para>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 - :<programlisting language="java">Transaction tx = BaseTransaction.getThreadTransaction(); -tx.addConnection("mydatanode", myConnection); </programlisting></para> - </section> -</chapter> http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-custom.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-custom.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-custom.xml deleted file mode 100644 index a8f00ea..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-custom.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" 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> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-ejbql.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-ejbql.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-ejbql.xml deleted file mode 100644 index 4c0afff..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-ejbql.xml +++ /dev/null @@ -1,94 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> -<section xmlns="http://docbook.org/ns/docbook" xml:id="ejbqlquery"> - <title>EJBQLQuery</title> - <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 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> - <para>Although most frequently EJBQLQuery is used as an alternative to SelectQuery, there - are also DELETE and UPDATE varieties available. <note> - <para>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. </para> - </note><programlisting language="java">EJBQLQuery select = new EJBQLQuery("select a FROM Artist a WHERE a.name = 'Salvador Dali'"); -List<Artist> artists = context.performQuery(select);</programlisting><programlisting language="java">EJBQLQuery delete = new EJBQLQuery("delete from Painting"); -context.performGenericQuery(delete);</programlisting><programlisting language="java">EJBQLQuery update = new EJBQLQuery("UPDATE Painting AS p SET p.name = 'P2' WHERE p.name = 'P1'"); -context.performGenericQuery(update);</programlisting>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:<programlisting language="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]; -}</programlisting>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:<programlisting language="java">EJBQLQuery query = new EJBQLQuery("select a.name FROM Artist a"); -List<String> names = context.performQuery(query);</programlisting> - - 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. - - <programlisting language="sql">select p from Painting p where p.paintingTitle in (?1,?2,?3)</programlisting> - - 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. - - <programlisting language="sql">select p from Painting p where p.paintingTitle in ?1</programlisting> - - The following example is functionally identical to the one prior. - - <programlisting language="sql">select p from Painting p where p.paintingTitle in (?1)</programlisting> - - </para> - <para> - It is <link linkend="expressions-to-ejbql">possible to convert</link> - an <link linkend="expressions">Expression</link> - object used with a <link linkend="selectquery">SelectQuery</link> - to EJBQL. Use the Expression#appendAsEJBQL methods for this purpose. - </para> - <para> - 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> - <listitem> - <para>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.</para> - </listitem> - <listitem> - <para>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".</para> - </listitem> - </itemizedlist> - </para> - </section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-mapped.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-mapped.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-mapped.xml deleted file mode 100644 index c3d7dd1..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-mapped.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" xml:id="mappedqueries"> - <title>MappedSelect and MappedExec</title> - <para> - <code>MappedSelect</code> and <code>MappedExec</code> 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 <code>MappedSelect</code> and <code>MappedExec</code> is (as reflected in their names) - whether underlying query intended to select data or just to perform some generic SQL code. - <note> - <para>These queries are "fluent" versions of deprecated <code>NamedQuery</code> class.</para> - </note> - </para> - <para> - Here is example of how to use <code>MappedSelect</code>: - <programlisting language="java"><![CDATA[List<Artist> results = MappedSelect.query("artistsByName", Artist.class)⨠- .param("name", "Picasso")⨠- .select(context);]]></programlisting> - </para> - <para> - And here is example of <code>MappedExec</code>: - <programlisting language="java"><![CDATA[QueryResult result = MappedExec.query("updateQuery")⨠- .param("var", "value")⨠- .execute(context); -System.out.println("Rows updated: " + result.firstUpdateCount());]]></programlisting> - </para> -</section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-namedquery.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-namedquery.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-namedquery.xml deleted file mode 100644 index 2287413..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-namedquery.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" 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<User> matchingUsers = context.performQuery(query); </programlisting> - <warning> - <para>This query is deprecated in favor of <code>MappedSelect</code> and <code>MappedExec</code></para> - </warning> - </para> - </section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-procedure.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-procedure.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-procedure.xml deleted file mode 100644 index dea2ce8..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-procedure.xml +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" xml:id="procedurequery"> - <title>ProcedureQuery</title> - <para>Stored procedures are mapped as separate objects in CayenneModeler. ProcedureQuery - provides a way to execute them with a certain set of parameters. Just like with - SQLTemplate, the outcome of a procedure can be anything - a single result set, mutliple - result sets, some data modification (returned as an update count), or a combination of - these. So use "performQuery" to get a single result set, and use "performGenericQuery" - for anything - else:<programlisting language="java">ProcedureQuery query = new ProcedureQuery("my_procedure", Artist.class); - -// Set "IN" parameter values -query.addParam("p1", "abc"); -query.addParam("p2", 3000); - -List<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"); - -query.addParam("p1", "abc"); -query.addParam("p2", 3000); - -QueryResponse response = context.performGenericQuery(query); </programlisting></para> - <para>A stored procedure can return data back to the application as result sets or via OUT - parameters. To simplify the processing of the query output, QueryResponse treats OUT - parameters as if it was a separate result set. If a stored procedure declares any OUT or - INOUT parameters, QueryResponse will contain their returned values in the very first - result - list:<programlisting language="java">ProcedureQuery query = new ProcedureQuery("my_procedure"); -QueryResponse response = context.performGenericQuery(query); - -// read OUT parameters -List out = response.firstList(); - -if(!out.isEmpty()) { - Map outParameterValues = (Map) outList.get(0); -}</programlisting></para> - <para>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.</para> - <para> - <warning> - <para>This query is superseded by <code>ProcedureCall</code> and generally shouldn't be used.</para> - </warning> - </para> -</section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-procedurecall.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-procedurecall.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-procedurecall.xml deleted file mode 100644 index 394a21e..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-procedurecall.xml +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" xml:id="procedurecallquery"> - <title>ProcedureCall</title> - <para>Stored procedures are mapped as separate objects in CayenneModeler. <code>ProcedureCall</code> - provides a way to execute them with a certain set of parameters. This query is a "fluent" version of - older <code>ProcedureQuery</code>. - Just like with <code>SQLTemplate</code>, 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: - <programlisting language="java"><![CDATA[List<Artist> result = ProcedureCall.query("my_procedure", Artist.class) - .param("p1", "abc") - .param("p2", 3000) - .call(context) - .firstList();]]></programlisting> - - <programlisting language="java"><![CDATA[// 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();]]></programlisting> - </para> - <para>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, <code>ProcedureResult</code> have convenient utility method to get them: - <programlisting language="java">ProcedureResult result = ProcedureCall.query("my_procedure") - .call(context); - -// read OUT parameters -Object out = result.getOutParam("out_param"); -</programlisting> - </para> - <para> - 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. - </para> -</section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-select.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-select.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-select.xml deleted file mode 100644 index 3e00d85..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-select.xml +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> -<section xmlns="http://docbook.org/ns/docbook" xml:id="selectquery"> - <title>ObjectSelect</title> - <section> - <title>Selecting objects</title> - <para> - <emphasis role="italic">ObjectSelect supersedes older SelectQuery. SelectQuery is still - available and supported. </emphasis> - </para> - <para>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: - <programlisting language="java">List<Artist> objects = ObjectSelect.query(Artist.class).select(context);</programlisting> - This returned all rows in the "ARTIST" table. If the logs were turned on, you might see the - following SQL printed: - <screen>INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 -INFO: === returned 5 row. - took 5 ms.</screen> - </para> - <para>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: - <programlisting language="java">List<Artist> objects = ObjectSelect.query(Artist.class) - .where(Artist.NAME.like("Pablo%")) - .select(context);</programlisting> - The SQL will look different this time: - <screen>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.</screen> - </para> - <para>ObjectSelect allows to assemble qualifier from parts, using "and" and "or" method to - chain then together: - <programlisting language="java">List<Artist> objects = ObjectSelect.query(Artist.class) - .where(Artist.NAME.like("A%")) - .and(Artist.DATE_OF_BIRTH.gt(someDate) - .select(context);</programlisting> - </para> - <para>To order the results of ObjectSelect, one or more orderings can be applied: - <programlisting language="java">List<Artist> objects = ObjectSelect.query(Artist.class) - .orderBy(Artist.DATE_OF_BIRTH.desc()) - .orderBy(Artist.NAME.asc()) - .select(context);</programlisting> - </para> - <para>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. - </para> - </section> - <section> - <title>Selecting individual columns</title> - <para> - <code>ObjectSelect</code> query can be used to fetch individual properties of objects via - type-safe API: - <programlisting language="java"><![CDATA[List<String> names = ObjectSelect.columnQuery(Artist.class, Artist.ARTIST_NAME) - .select(context);]]></programlisting> - And here is example of selecting several properties, note that result will be <code>Object[]</code>: - <programlisting language="java"><![CDATA[List<Object[]> nameAndDate = ObjectSelect - .columnQuery(Artist.class, Artist.ARTIST_NAME, Artist.DATE_OF_BIRTH) - .select(context);]]></programlisting> - </para> - </section> - <section> - <title>Selecting aggregate functions</title> - <para> - ObjectSelect query supports usage of aggregate functions. - Most common variant of aggregation is selecting count of records, this can be done really easy: - <programlisting language="java"><![CDATA[long count = ObjectSelect.query(Artist.class).selectCount(context);]]></programlisting> - But you can use aggregates in more cases, even combine selecting individual properties and aggregates: - <programlisting language="java"><![CDATA[// 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"); -}]]></programlisting> - Here is generated <code>SQL</code> for this query: - <programlisting language="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</programlisting> - </para> - </section> -</section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-selectbyid.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-selectbyid.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-selectbyid.xml deleted file mode 100644 index 59940f9..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-selectbyid.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" xml:id="selectbyid"> - <title>SelectById</title> - <para> - This query allows to search objects by their ID. - It's introduced in Cayenne 4.0 and uses new "fluent" API same as <code>ObjectSelect</code> query. - </para> - <para> - Here is example of how to use it: - <programlisting language="java"><![CDATA[Artist artistWithId1 = SelectById.query(Artist.class, 1) - .prefetch(Artist.PAINTING_ARRAY.joint()) - .localCache() - .selectOne(context);]]></programlisting> - </para> -</section> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cayenne/blob/cde78f0b/docs/docbook/cayenne-guide/src/docbkx/queries-sqlselect.xml ---------------------------------------------------------------------- diff --git a/docs/docbook/cayenne-guide/src/docbkx/queries-sqlselect.xml b/docs/docbook/cayenne-guide/src/docbkx/queries-sqlselect.xml deleted file mode 100644 index e488fab..0000000 --- a/docs/docbook/cayenne-guide/src/docbkx/queries-sqlselect.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ~ 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. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> -<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sqlselect"> - <title>SQLSelect and SQLExec</title> - <para> - <code>SQLSelect</code> and <code>SQLExec</code> are essentially a "fluent" versions of older <code>SQLTemplate</code> query. - <code>SQLSelect</code> can be used (as name suggests) to select custom data in form of entities, separate columns or collection of <code>DataRow</code>. - <code>SQLExec</code> is designed to just execute any raw SQL code (e.g. updates, deletes, DDLs, etc.) - These queries support all directives described in <link linkend="sqltemplate">SQLTemplate</link> section. - </para> - <para> - Here is example of how to use <code>SQLSelect</code>: - <programlisting language="java"><![CDATA[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);]]></programlisting> - </para> - <para> - And here is example of how to use <code>SQLExec</code>: - <programlisting language="java"><![CDATA[int inserted = SQLExec - .query("INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME) VALUES (#bind($id), #bind($name))") - .paramsArray(55, "Picasso") - .update(context);]]></programlisting> - </para> -</section> \ No newline at end of file