| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title xmlns:d="http://docbook.org/ns/docbook">Chapter 7. Expressions</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 3.1 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 3.1"><link rel="home" href="index.html" title="Cayenne Guide"><link rel="up" href="cayenne-guide-part2.html" title="Part II. Cayenne Framework"><link rel="prev" href="persistent-objects-objectcontext.html" title="Chapter 6. Persistent Objects and ObjectContext"><link rel="next" href="orderings.html" title="Chapter 8. Orderings"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-7036673-1']); |
| _gaq.push(['_trackPageview']); |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| </script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.3.1 (3.1)</th><th align="center">Chapter 7. Expressions</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="persistent-objects-objectcontext.html">Prev</a> </td><th width="60%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Part II. Cayenne Framework</a></th><td width="20%" align="right"> <a accesskey="n" href="orderings.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 7. Expressions"><div class="titlepage"><div><div><h2 class="title"><a name="expressions"></a>Chapter 7. Expressions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="expressions.html#expressions-overview">Expressions Overview</a></span></dt><dt><span class="section"><a href="expressions.html#path-expressions">Path Expressions</a></span></dt><dt><span class="section"><a href="expressions.html#expressions-from-strings">Creating Expressions from Strings </a></span></dt><dt><span class="section"><a href="expressions.html#expressions-with-expressionfactory">Creating Expressions with API</a></span></dt><dt><span class="section"><a href="expressions.html#expressions-in-memory">Evaluating Expressions in Memory</a></span></dt></dl></div><div class="section" title="Expressions Overview"><div class="titlepage"><div><div><h2 class="title"><a name="expressions-overview"></a>Expressions Overview</h2></div></div></div><p>Cayenne provides a simple yet powerful object-based expression language. The most common |
| usese of expressions are to build qualifiers and orderings of queries that are later |
| converted to SQL by Cayenne and to evaluate in-memory against specific objects (to |
| access certain values in the object graph or to perform in-memory object filtering and |
| sorting). Cayenne provides API to build expressions in the code and a parser to create |
| expressions from strings.</p></div><div class="section" title="Path Expressions"><div class="titlepage"><div><div><h2 class="title"><a name="path-expressions"></a>Path Expressions</h2></div></div></div><p>Before discussing how to build expressions, it is important to understand one group of |
| expressions widely used in Cayenne - path expressions. There are two types of path |
| expressions - object and database, used for navigating graphs of connected objects or |
| joined DB tables respectively. Object paths are much more commonly used, as after all |
| Cayenne is supposed to provide a degree of isolation of the object model from the |
| database. However database paths are helpful in certain situations. General structure of |
| path expressions is the following:</p><pre class="programlisting"> [db:]segment[+][.segment[+]...]</pre><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>"db:" is an optional prefix indicating that the following path is a DB |
| path. Otherwise it is an object path.</p></li><li class="listitem"><p>"segment" is a name of a property (relationship or attribute in Cayenne |
| terms) in the path. Path must have at least one segment; segments are |
| separated by dot (".").</p></li><li class="listitem"><p>"+" An "OUTER JOIN" path component. Currently "+" only has effect when |
| translated to SQL as OUTER JOIN. When evaluating expressions in memory, it |
| is ignored.</p></li></ul></div><p>An object path expression represents a chain of property names rooted in a certain |
| (unspecified during expression creation) object and "navigating" to its related value. |
| E.g. a path expression "artist.name" might be a property path starting from a Painting |
| object, pointing to the related Artist object, and then to its name attribute. A few |
| more examples:</p><p> |
| </p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>"name" - can be used to navigate (read) the "name" property of a Person |
| (or any other type of object that has a "name" property).</p></li><li class="listitem"><p>"artist.exhibits.closingDate" - can be used to navigate to a closing date |
| of any of the exhibits of a Painting's Artist object.</p></li><li class="listitem"><p>"artist.exhibits+.closingDate" - same as the previous example, but when |
| translated into SQL, an OUTER JOIN will be used for "exhibits".</p></li></ul></div><p> |
| </p><p>Similarly a database path expression is a dot-separated path through DB table joins |
| and columns. In Cayenne joins are mapped as DbRelationships with some symbolic names |
| (the closest concept to DbRelationship name in the DB world is a named foreign key |
| constraint. But DbRelationship names are usually chosen arbitrarily, without regard to |
| constraints naming or even constraints presence). A database path therefore might look |
| like this - "db:dbrelationshipX.dbrelationshipY.COLUMN_Z". More specific examples:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>"db:NAME" - can be used to navigate to the value of "NAME" column of some |
| unspecified table.</p></li><li class="listitem"><p>"db:artist.artistExhibits.exhibit.CLOSING_DATE" - can be used to match a |
| closing date of any of the exhibits of a related artist record.</p></li></ul></div><p>Cayenne supports "aliases" in path Expressions. E.g. the same expression can be |
| written using explicit path or an alias:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>"artist.exhibits.closingDate" - full path</p></li><li class="listitem"><p>"e.closingDate" - alias "e" is used for "artist.exhibits".</p></li></ul></div><p>SelectQuery using the second form of the path expression must be made |
| aware of the alias via <span class="italic"> |
| "SelectQuery.aliasPathSplits(..)"</span>, otherwise an Exception will be |
| thrown. The main use of aliases is to allow users to control how SQL joins are generated |
| if the same path is encountered more than once in any given Expression. Each alias for |
| any given path would result in a separate join. Without aliases, a single join will be |
| used for a group of matching paths.</p></div><div class="section" title="Creating Expressions from Strings"><div class="titlepage"><div><div><h2 class="title"><a name="expressions-from-strings"></a>Creating Expressions from Strings </h2></div></div></div><p>While in most cases users are likely to rely on API from the following section for |
| expression creation, we'll start by showing String expressions, as this will help |
| understanding the semantics. A Cayenne expression can be represented as a String, which |
| can be later converted to an expression object using <code class="code">Expression.fromString</code> |
| static method. Here is an |
| example:</p><pre class="programlisting">String expString = "name like 'A%' and price < 1000"; |
| Expression exp = Expression.fromString(expString);</pre><p>This |
| particular expression may be used to match Paintings with names that start with "A" and |
| a price less than $1000. While this example is pretty self-explanatory, there are a few |
| points worth mentioning. "name" and "price" here are object paths discussed earlier. As |
| always, paths themselves are not attached to a specific root entity and can be applied |
| to any entity that has similarly named attributes or relationships. So when we are |
| saying that this expression "may be used to match Paintings", we are implying that there |
| may be other entities, for which this expression is valid. Now the expression details... </p><p><span class="italic">Character constants</span> that are not paths or numeric values |
| should be enclosed in single or double quotes. Two of the expressions below are |
| equivalent:</p><pre class="programlisting">name = 'ABC' |
| |
| // double quotes are escaped inside Java Strings of course |
| name = \"ABC\"</pre><p><span class="italic">Case sensitivity.</span> Expression operators are all case |
| sensitive and are usually lowercase. Complex words follow the java camel-case |
| style:</p><pre class="programlisting">// valid |
| name likeIgnoreCase 'A%' |
| |
| // invalid - will throw a parse exception |
| name LIKEIGNORECASE 'A%'</pre><p><span class="italic">Grouping with parenthesis:</span> |
| </p><pre class="programlisting">value = (price + 250.00) * 3</pre><p> |
| </p><p><span class="italic">Path prefixes.</span> Object expressions are unquoted strings, |
| optionally prefixed by "obj:" (usually they are not prefixed at all actually). Database |
| expressions are always prefixed with "db:". A special kind of prefix, not discussed yet |
| is "enum:" that prefixes an enumeration |
| constant:</p><pre class="programlisting">// object path |
| name = 'Salvador Dali' |
| |
| // same object path - a rarely used form |
| obj:name = 'Salvador Dali' |
| |
| // multi-segment object path |
| artist.name = 'Salvador Dali' |
| |
| // db path |
| db:NAME = 'Salvador Dali' |
| |
| // enumeration constant |
| name = enum:org.foo.EnumClass.VALUE1</pre><p> |
| <span class="italic">Binary conditions</span> are expressions that contain a path |
| on the left, a value on the right, and some operation between them, such as equals, |
| like, etc. They can be used as qualifiers in |
| SelectQueries:</p><pre class="programlisting">name like 'A%'</pre><p> |
| <span class="italic">Named parameters.</span> Expressions can have named parameters (names that |
| start with "$"). Parameterized expressions allow to create reusable expression |
| templates. Also if an Expression contains a complex object that doesn't have a simple |
| String representation (e.g. a Date, a DataObject, an ObjectId), parameterizing such |
| expression is the only way to represent it as String. Here are some |
| examples:</p><pre class="programlisting">Expression template = Expression.fromString("name = $name"); |
| ... |
| Map p1 = Collections.singletonMap("name", "Salvador Dali"); |
| Expression qualifier1 = template.expWithParameters(p1); |
| ... |
| Map p2 = Collections.singletonMap("name", "Monet"); |
| Expression qualifier2 = template.expWithParameters(p2);</pre><p>To |
| create a named parameterized expression with a LIKE clause, SQL wildcards must be part |
| of the values in the Map and not the expression string |
| itself:</p><pre class="programlisting">Expression template = Expression.fromString("name like $name"); |
| ... |
| Map p1 = Collections.singletonMap("name", "Salvador%"); |
| Expression qualifier1 = template.expWithParameters(p1);</pre><p>When |
| matching on a relationship, parameters can be Persistent objects or |
| ObjectIds:</p><pre class="programlisting">Expression template = Expression.fromString("artist = $artist"); |
| ... |
| Artist dali = // asume we fetched this one already |
| Map p1 = Collections.singletonMap("artist", dali); |
| Expression qualifier1 = template.expWithParameters(p1);</pre><p>Uninitialized |
| parameters will be automatically pruned from expressions, so a user can omit some |
| parameters when creating an expression from a parameterized |
| template:</p><pre class="programlisting">Expression template = Expression.fromString("name like $name and dateOfBirth > $date"); |
| ... |
| Map p1 = Collections.singletonMap("name", "Salvador%"); |
| Expression qualifier1 = template.expWithParameters(p1); |
| |
| // qualifier1 is now equals to "name like 'Salvador%'", the 'dateOfBirth' condition was |
| // pruned, as no value was specified for the $date parameter</pre><p><span class="italic">Null handling.</span> Handling of Java nulls as operands |
| is no different from normal values. Instead of using special conditional operators, like |
| SQL does (IS NULL, IS NOT NULL), "=" and "!=" expressions can be used directly with null |
| values. It is up to Cayenne to translate expressions with nulls to the valid SQL.</p><p> |
| </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>A formal definition of all possible valid expressions in a form of JavaCC |
| grammar is provided in Appendix C</p></div><p> |
| </p></div><div class="section" title="Creating Expressions with API"><div class="titlepage"><div><div><h2 class="title"><a name="expressions-with-expressionfactory"></a>Creating Expressions with API</h2></div></div></div><p>Creating expressions from Strings is a powerful and dynamic approach, however a safer |
| alternative is to use Java API. It provides some degree of compile-time checking of |
| expressions validity. The API is cenetred around ExpressionFactory class, and the |
| Expression class. ExpressionFactory contains a number of rather self-explanatory factory |
| methods. We won't be going over all of them in detail, but will rather show a few |
| general examples and some gotchas. </p><p>The following code recreates the expression from the previous chapter, but now using |
| expression |
| API:</p><pre class="programlisting">// String expression: name like 'A%' and price < 1000 |
| Expression e1 = ExpressionFactory.likeExp(Painting.NAME_PROPERTY, "A%"); |
| Expression e2 = ExpressionFactory.lessExp(Painting.PRICE_PROPERTY, 1000); |
| Expression finalExp = e1.andExp(e2); </pre><p>This |
| is more verbose than creating it from String, but it is also more resilient to the |
| entity properties renaming and precludes semantic errors in the expression String.</p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The last line in the example above shows how to create a new expression by |
| "chaining" 2 other epxressions. A common error when chaining expressions is to |
| assume that "andExp" and "orExp" append another expression to the current |
| expression. In fact a new expression is created. I.e. Expression API treats |
| existing expressions as immutable.</p></div><p>As discussed earlier, Cayenne supports aliases in path Expressions, allowing to |
| control how SQL joins are generated if the same path is encountered more than once in |
| the same Expression. Two ExpressionFactory methods allow to implicitly generate aliases |
| to "split" match paths into individual joins if |
| needed:</p><pre class="programlisting">Expression matchAllExp(String path, Collection values) |
| Expression matchAllExp(String path, Object... values)</pre><p>"Path" argument to both of these methods can use a split character (a pipe symbol '|') |
| instead of dot to indicate that relationship following a path should be split into a |
| separate set of joins, one per collection value. There can only be one split at most in |
| any given path. Split must always precede a relationship. E.g. "|exhibits.paintings", |
| "exhibits|paintings", etc. Internally Cayenne would generate distinct aliases for each |
| of the split expressions, forcing separate joins.</p></div><div class="section" title="Evaluating Expressions in Memory"><div class="titlepage"><div><div><h2 class="title"><a name="expressions-in-memory"></a>Evaluating Expressions in Memory</h2></div></div></div><p>When used in a query, an expression is converted to SQL WHERE clause (or ORDER BY |
| clause) by Cayenne during query execution. Thus the actual evaluation against the data |
| is done by the database engine. However the same expressions can also be used for |
| accessing object properties, calculating values, in-memory filtering. </p><p>Checking whether an object satisfies an |
| expression:</p><pre class="programlisting">Expression e = ExpressionFactory.inExp(User.NAME_PROPERTY, "John", "Bob"); |
| User user = ... |
| if(e.match(user)) { |
| ... |
| }</pre><p>Reading |
| property |
| value:</p><pre class="programlisting">Expression e = Expression.fromString(User.NAME_PROPERTY); |
| String name = e.evaluate(user);</pre><p>Filtering a list of |
| objects:</p><pre class="programlisting">Expression e = ExpressionFactory.inExp(User.NAME_PROPERTY, "John", "Bob"); |
| List<User> unfiltered = ... |
| List<User> filtered = e.filterObjects(unfiltered);</pre><p> |
| </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>Current limitation of in-memory expressions is that no collections are |
| permitted in the property path.</p></div><p> |
| </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="persistent-objects-objectcontext.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="orderings.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. Persistent Objects and ObjectContext </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 8. Orderings</td></tr></table></div></body></html> |