Updated Documentation
36
site/reference/html/css/highlight.css
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
borrowed from: https://raw.github.com/SpringSource/spring-data-jpa/master/src/docbkx/resources/css/highlight.css
|
||||
code highlight CSS resemblign the Eclipse IDE default color schema
|
||||
@author Costin Leau
|
||||
*/
|
||||
|
||||
.hl-keyword {
|
||||
color: #7F0055;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hl-comment {
|
||||
color: #3F5F5F;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hl-multiline-comment {
|
||||
color: #3F5FBF;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hl-tag {
|
||||
color: #3F7F7F;
|
||||
}
|
||||
|
||||
.hl-attribute {
|
||||
color: #7F007F;
|
||||
}
|
||||
|
||||
.hl-value {
|
||||
color: #2A00FF;
|
||||
}
|
||||
|
||||
.hl-string {
|
||||
color: #2A00FF;
|
||||
}
|
114
site/reference/html/css/html.css
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
borrowed from: https://raw.github.com/SpringSource/spring-data-jpa/master/src/docbkx/resources/css/html.css
|
||||
*/
|
||||
|
||||
@IMPORT url("highlight.css");
|
||||
|
||||
html {
|
||||
padding: 0pt;
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-left: 15%;
|
||||
margin-right: 15%;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid gray;
|
||||
background: gray;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5 {
|
||||
color: #234623;
|
||||
font-weight: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
margin-bottom: 0em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
pre {
|
||||
line-height: 1.0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
table code {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
pre.programlisting {
|
||||
font-size: 1em;
|
||||
padding: 3pt 3pt;
|
||||
border: 1pt solid black;
|
||||
background: #eeeeee;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.table {
|
||||
margin: 1em;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.table table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.table td {
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
float: right;
|
||||
margin: 10px 0 10px 30px;
|
||||
padding: 10px 20px 20px 20px;
|
||||
width: 33%;
|
||||
border: 1px solid black;
|
||||
background-color: #F4F4F4;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mediaobject {
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.legalnotice {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
p.releaseinfo {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
p.pubdate {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
}
|
||||
|
||||
span.productname {
|
||||
font-size: 200%;
|
||||
font-weight: bold;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 125%;
|
||||
}
|
BIN
site/reference/html/images/admons/blank.png
Normal file
After Width: | Height: | Size: 374 B |
BIN
site/reference/html/images/admons/caution.gif
Normal file
After Width: | Height: | Size: 743 B |
BIN
site/reference/html/images/admons/caution.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
site/reference/html/images/admons/draft.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
site/reference/html/images/admons/home.gif
Normal file
After Width: | Height: | Size: 321 B |
BIN
site/reference/html/images/admons/home.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/important.gif
Normal file
After Width: | Height: | Size: 1003 B |
BIN
site/reference/html/images/admons/important.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
site/reference/html/images/admons/next.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/next.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/note.gif
Normal file
After Width: | Height: | Size: 580 B |
BIN
site/reference/html/images/admons/note.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
site/reference/html/images/admons/prev.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/prev.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/tip.gif
Normal file
After Width: | Height: | Size: 598 B |
BIN
site/reference/html/images/admons/tip.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
site/reference/html/images/admons/toc-blank.png
Normal file
After Width: | Height: | Size: 318 B |
BIN
site/reference/html/images/admons/toc-minus.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
site/reference/html/images/admons/toc-plus.png
Normal file
After Width: | Height: | Size: 264 B |
BIN
site/reference/html/images/admons/up.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/up.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
site/reference/html/images/admons/warning.gif
Normal file
After Width: | Height: | Size: 613 B |
BIN
site/reference/html/images/admons/warning.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
site/reference/html/images/callouts/1.png
Normal file
After Width: | Height: | Size: 329 B |
BIN
site/reference/html/images/callouts/10.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
site/reference/html/images/callouts/11.png
Normal file
After Width: | Height: | Size: 565 B |
BIN
site/reference/html/images/callouts/12.png
Normal file
After Width: | Height: | Size: 617 B |
BIN
site/reference/html/images/callouts/13.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
site/reference/html/images/callouts/14.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
site/reference/html/images/callouts/15.png
Normal file
After Width: | Height: | Size: 640 B |
BIN
site/reference/html/images/callouts/2.png
Normal file
After Width: | Height: | Size: 353 B |
BIN
site/reference/html/images/callouts/3.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
site/reference/html/images/callouts/4.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
site/reference/html/images/callouts/5.png
Normal file
After Width: | Height: | Size: 348 B |
BIN
site/reference/html/images/callouts/6.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
site/reference/html/images/callouts/7.png
Normal file
After Width: | Height: | Size: 344 B |
BIN
site/reference/html/images/callouts/8.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
site/reference/html/images/callouts/9.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
site/reference/html/images/logo.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
site/reference/html/images/xdev-spring_logo.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
938
site/reference/html/index.html
Normal file
@ -0,0 +1,938 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Spring Data Elasticsearch</title><link rel="stylesheet" href="css/html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.72.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="d0e1"></a>Spring Data Elasticsearch</h1></div><div><div xmlns:fo="http://www.w3.org/1999/XSL/Format" class="authorgroup"><h2>Authors</h2><p></p><span class="author"><span class="firstname">BioMed Central</span> <span class="surname">Development Team</span></span></div></div><div><p class="copyright">Copyright © 2013 The original author(s)</p></div><div><div class="legalnotice"><a name="d0e11"></a><p>
|
||||
Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not
|
||||
charge any fee for
|
||||
such copies and further provided that each copy
|
||||
contains this
|
||||
Copyright Notice, whether
|
||||
distributed in print or electronically.
|
||||
</p></div></div></div><hr></div><div class="toc"><dl><dt><span class="preface"><a href="#preface">Preface</a></span></dt><dd><dl><dt><span class="section"><a href="#project">1. Project Metadata</a></span></dt><dt><span class="section"><a href="#requirements">2. Requirements</a></span></dt></dl></dd><dt><span class="part"><a href="#reference">I. Reference Documentation</a></span></dt><dd><dl><dt><span class="chapter"><a href="#repositories">1. Repositories</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.introduction">1.1. Introduction</a></span></dt><dt><span class="section"><a href="#repositories.core-concepts">1.2. Core concepts</a></span></dt><dt><span class="section"><a href="#repositories.query-methods">1.3. Query methods</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.definition">1.3.1. Defining repository interfaces</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.definition-tuning">1.3.1.1. Fine tuning repository definition</a></span></dt></dl></dd><dt><span class="section"><a href="#repositories.query-methods.details">1.3.2. Defining query methods</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.query-methods.query-lookup-strategies">1.3.2.1. Query lookup strategies</a></span></dt><dt><span class="section"><a href="#repositories.query-methods.query-creation">1.3.2.2. Query creation</a></span></dt><dt><span class="section"><a href="#repositories.special-parameters">1.3.2.3. Special parameter handling</a></span></dt></dl></dd><dt><span class="section"><a href="#repositories.create-instances">1.3.3. Creating repository instances</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.create-instances.spring">1.3.3.1. XML Configuration</a></span></dt><dt><span class="section"><a href="#repositories.create-instances.java-config">1.3.3.2. JavaConfig</a></span></dt><dt><span class="section"><a href="#repositories.create-instances.standalone">1.3.3.3. Standalone usage</a></span></dt></dl></dd></dl></dd><dt><span class="section"><a href="#repositories.custom-implementations">1.4. Custom implementations</a></span></dt><dd><dl><dt><span class="section"><a href="#repositories.single-repository-behaviour">1.4.1. Adding behaviour to single repositories</a></span></dt><dt><span class="section"><a href="#repositories.custom-behaviour-for-all-repositories">1.4.2. Adding custom behaviour to all repositories</a></span></dt></dl></dd><dt><span class="section"><a href="#d0e637">1.5. Extensions</a></span></dt><dd><dl><dt><span class="section"><a href="#web-domain-class-binding">1.5.1. Domain class web binding for Spring MVC</a></span></dt><dt><span class="section"><a href="#web-pagination">1.5.2. Web pagination</a></span></dt><dt><span class="section"><a href="#d0e805">1.5.3. Repository populators</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#elasticsearch.repositories">2. Elasticsearch Repositories</a></span></dt><dd><dl><dt><span class="section"><a href="#elasticsearch.introduction">2.1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="#elasticsearch.namespace">2.1.1. Spring Namespace</a></span></dt><dt><span class="section"><a href="#elasticsearch.annotation">2.1.2. Annotation based configuration</a></span></dt><dt><span class="section"><a href="#elasticsearch.cdi">2.1.3. Elasticsearch Repositores using CDI</a></span></dt></dl></dd><dt><span class="section"><a href="#elasticsearch.query-methods">2.2. Query methods</a></span></dt><dd><dl><dt><span class="section"><a href="#elasticsearch.query-methods.finders">2.2.1. Query lookup strategies</a></span></dt><dt><span class="section"><a href="#elasticsearch.query-methods.criterions">2.2.2. Query creation</a></span></dt><dt><span class="section"><a href="#elasticsearch.query-methods.at-query">2.2.3. Using @Query Annotation</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#elasticsearch.misc">3. Miscellaneous Elasticsearch Operation Support</a></span></dt><dd><dl><dt><span class="section"><a href="#elasticsearch.misc.filter">3.1. Filter Builder</a></span></dt></dl></dd></dl></dd><dt><span class="part"><a href="#appendix">II. Appendix</a></span></dt><dd><dl><dt><span class="appendix"><a href="#namespace-reference">A. Namespace reference</a></span></dt><dd><dl><dt><span class="section"><a href="#namespace-dao-config">A.1. The <code class="code"><repositories /></code> element</a></span></dt></dl></dd><dt><span class="appendix"><a href="#repository-query-keywords">B. Repository query keywords</a></span></dt><dd><dl><dt><span class="section"><a href="#d0e1401">B.1. Supported query keywords</a></span></dt></dl></dd></dl></dd></dl></div><div class="preface" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="preface"></a>Preface</h2></div></div></div><p>The Spring Data Elasticsearch project applies core Spring concepts to
|
||||
the
|
||||
development of solutions using the Elasticsearch Search Engine.
|
||||
We have povided a "template" as a high-level abstraction for
|
||||
storing,querying,sorting and faceting documents. You will notice similarities
|
||||
to the Spring data solr and
|
||||
mongodb support in the Spring Framework.
|
||||
</p><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="project"></a>1. Project Metadata</h2></div></div></div><div class="itemizedlist"><ul type="disc" compact><li><p>
|
||||
Version Control -
|
||||
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="git://github.com/BioMedCentralLtd/spring-data-elasticsearch.git" target="_top">git://github.com/BioMedCentralLtd/spring-data-elasticsearch.git
|
||||
</a>
|
||||
</p></li></ul></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="requirements"></a>2. Requirements</h2></div></div></div><p>
|
||||
Requires
|
||||
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="http://www.elasticsearch.org/download/" target="_top">Elasticsearch</a>
|
||||
0.20.2 and above or optional dependency or not even that if you are using Embedded Node Client
|
||||
</p></div></div><div class="part" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="reference"></a>Part I. Reference Documentation</h1></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="repositories"></a>Chapter 1. Repositories</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="repositories.introduction"></a>1.1. Introduction</h2></div></div></div><p>Implementing a data access layer of an application has been
|
||||
cumbersome for quite a while. Too much boilerplate code had to be written.
|
||||
Domain classes were anemic and not designed in a real object oriented or
|
||||
domain driven manner.</p><p>Using both of these technologies makes developers life a lot easier
|
||||
regarding rich domain model's persistence. Nevertheless the amount of
|
||||
boilerplate code to implement repositories especially is still quite high.
|
||||
So the goal of the repository abstraction of Spring Data is to reduce the
|
||||
effort to implement data access layers for various persistence stores
|
||||
significantly.</p><p>The following chapters will introduce the core concepts and
|
||||
interfaces of Spring Data repositories in general for detailled
|
||||
information on the specific features of a particular store consult the
|
||||
later chapters of this document.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/admons/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>As this part of the documentation is pulled in from Spring Data
|
||||
Commons we have to decide for a particular module to be used as example.
|
||||
The configuration and code samples in this chapter are using the JPA
|
||||
module. Make sure you adapt e.g. the XML namespace declaration, types to
|
||||
be extended to the equivalents of the module you're actually
|
||||
using.</p></td></tr></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="repositories.core-concepts"></a>1.2. Core concepts</h2></div></div></div><p>The central interface in Spring Data repository abstraction is
|
||||
<code class="interfacename">Repository</code> (probably not that much of a
|
||||
surprise). It is typeable to the domain class to manage as well as the id
|
||||
type of the domain class. This interface mainly acts as marker interface
|
||||
to capture the types to deal with and help us when discovering interfaces
|
||||
that extend this one. Beyond that there's
|
||||
<code class="interfacename">CrudRepository</code> which provides some
|
||||
sophisticated functionality around CRUD for the entity being
|
||||
managed.</p><div class="example"><a name="repositories.repository"></a><p class="title"><b>Example 1.1. <code class="interfacename">CrudRepository</code> interface</b></p><div class="example-contents"><div class="programlistingco"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> CrudRepository<T, ID <span class="hl-keyword">extends</span> Serializable>
|
||||
<span class="hl-keyword">extends</span> Repository<T, ID> {
|
||||
<span class="co"><img src="images/callouts/1.png" alt="(1)"></span>
|
||||
T save(T entity);
|
||||
<span class="co"><img src="images/callouts/2.png" alt="(2)"></span>
|
||||
T findOne(ID primaryKey);
|
||||
<span class="co"><img src="images/callouts/3.png" alt="(3)"></span>
|
||||
Iterable<T> findAll();
|
||||
|
||||
Long count();
|
||||
<span class="co"><img src="images/callouts/4.png" alt="(4)"></span>
|
||||
<span class="hl-keyword">void</span> delete(T entity);
|
||||
<span class="co"><img src="images/callouts/5.png" alt="(5)"></span>
|
||||
<span class="hl-keyword">boolean</span> exists(ID primaryKey);
|
||||
<span class="co"><img src="images/callouts/6.png" alt="(6)"></span>
|
||||
<span class="hl-comment">// … more functionality omitted.</span>
|
||||
}</pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><img src="images/callouts/1.png" alt="1" border="0"></td><td valign="top" align="left"><p>Saves the given entity.</p></td></tr><tr><td width="5%" valign="top" align="left"><img src="images/callouts/2.png" alt="2" border="0"></td><td valign="top" align="left"><p>Returns the entity identified by the given id.</p></td></tr><tr><td width="5%" valign="top" align="left"><img src="images/callouts/3.png" alt="3" border="0"></td><td valign="top" align="left"><p>Returns all entities.</p></td></tr><tr><td width="5%" valign="top" align="left"><img src="images/callouts/4.png" alt="4" border="0"></td><td valign="top" align="left"><p>Returns the number of entities.</p></td></tr><tr><td width="5%" valign="top" align="left"><img src="images/callouts/5.png" alt="5" border="0"></td><td valign="top" align="left"><p>Deletes the given entity.</p></td></tr><tr><td width="5%" valign="top" align="left"><img src="images/callouts/6.png" alt="6" border="0"></td><td valign="top" align="left"><p>Returns whether an entity with the given id exists.</p></td></tr></table></div></div></div></div><br class="example-break"><p>Usually we will have persistence technology specific sub-interfaces
|
||||
to include additional technology specific methods. We will now ship
|
||||
implementations for a variety of Spring Data modules that implement this
|
||||
interface.</p><p>On top of the <code class="interfacename">CrudRepository</code> there is
|
||||
a <code class="interfacename">PagingAndSortingRepository</code> abstraction
|
||||
that adds additional methods to ease paginated access to entities:</p><div class="example"><a name="d0e116"></a><p class="title"><b>Example 1.2. PagingAndSortingRepository</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> PagingAndSortingRepository<T, ID <span class="hl-keyword">extends</span> Serializable> <span class="hl-keyword">extends</span> CrudRepository<T, ID> {
|
||||
|
||||
Iterable<T> findAll(Sort sort);
|
||||
|
||||
Page<T> findAll(Pageable pageable);
|
||||
}</pre></div></div><br class="example-break"><p>Accessing the second page of <code class="classname">User</code> by a page
|
||||
size of 20 you could simply do something like this:</p><pre class="programlisting">PagingAndSortingRepository<User, Long> repository = <span class="hl-comment">// … get access to a bean</span>
|
||||
Page<User> users = repository.findAll(<span class="hl-keyword">new</span> PageRequest(1, 20));</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="repositories.query-methods"></a>1.3. Query methods</h2></div></div></div><p>Next to standard CRUD functionality repositories are usually queries
|
||||
on the underlying datastore. With Spring Data declaring those queries
|
||||
becomes a four-step process:</p><div class="orderedlist"><ol type="1"><li><p>Declare an interface extending
|
||||
<code class="interfacename">Repository</code> or one of its sub-interfaces
|
||||
and type it to the domain class it shall handle.</p><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> PersonRepository <span class="hl-keyword">extends</span> Repository<User, Long> { … }</pre></li><li><p>Declare query methods on the interface.</p><pre class="programlisting">List<Person> findByLastname(String lastname);</pre></li><li><p>Setup Spring to create proxy instances for those
|
||||
interfaces.</p><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans:beans</span> <span class="hl-attribute">xmlns:beans</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/data/jpa"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/data/jpa
|
||||
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repositories"</span> />
|
||||
|
||||
<<span class="hl-tag">/beans</span>></pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/admons/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Note that we use the JPA namespace here just by example. If
|
||||
you're using the repository abstraction for any other store you need
|
||||
to change this to the appropriate namespace declaration of your
|
||||
store module which should be exchanging <code class="code">jpa</code> in favor of
|
||||
e.g. <code class="code">mongodb</code>.</p></td></tr></table></div></li><li><p>Get the repository instance injected and use it.</p><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">class</span> SomeClient {
|
||||
|
||||
@Autowired
|
||||
<span class="hl-keyword">private</span> PersonRepository repository;
|
||||
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> doSomething() {
|
||||
List<Person> persons = repository.findByLastname(<span class="hl-string">"Matthews"</span>);
|
||||
}</pre></li></ol></div><p>At this stage we barely scratched the surface of what's possible
|
||||
with the repositories but the general approach should be clear. Let's go
|
||||
through each of these steps and figure out details and various options
|
||||
that you have at each stage.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="repositories.definition"></a>1.3.1. Defining repository interfaces</h3></div></div></div><p>As a very first step you define a domain class specific repository
|
||||
interface. It's got to extend <code class="interfacename">Repository</code>
|
||||
and be typed to the domain class and an ID type. If you want to expose
|
||||
CRUD methods for that domain type, extend
|
||||
<code class="interfacename">CrudRepository</code> instead of
|
||||
<code class="interfacename">Repository</code>.</p><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.definition-tuning"></a>1.3.1.1. Fine tuning repository definition</h4></div></div></div><p>Usually you will have your repository interface extend
|
||||
<code class="interfacename">Repository</code>,
|
||||
<code class="interfacename">CrudRepository</code> or
|
||||
<code class="interfacename">PagingAndSortingRepository</code>. If you
|
||||
don't like extending Spring Data interfaces at all you can also
|
||||
annotate your repository interface with
|
||||
<code class="interfacename">@RepositoryDefinition</code>. Extending
|
||||
<code class="interfacename">CrudRepository</code> will expose a complete
|
||||
set of methods to manipulate your entities. If you would rather be
|
||||
selective about the methods being exposed, simply copy the ones you
|
||||
want to expose from <code class="interfacename">CrudRepository</code> into
|
||||
your domain repository.</p><div class="example"><a name="d0e205"></a><p class="title"><b>Example 1.3. Selectively exposing CRUD methods</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">interface</span> MyBaseRepository<T, ID <span class="hl-keyword">extends</span> Serializable> <span class="hl-keyword">extends</span> Repository<T, ID> {
|
||||
T findOne(ID id);
|
||||
T save(T entity);
|
||||
}
|
||||
|
||||
<span class="hl-keyword">interface</span> UserRepository <span class="hl-keyword">extends</span> MyBaseRepository<User, Long> {
|
||||
|
||||
User findByEmailAddress(EmailAddress emailAddress);
|
||||
}</pre></div></div><br class="example-break"><p>In the first step we define a common base interface for all our
|
||||
domain repositories and expose <code class="methodname">findOne(…)</code> as
|
||||
well as <code class="methodname">save(…)</code>.These methods will be routed
|
||||
into the base repository implementation of the store of your choice
|
||||
because they are matching the method signatures in
|
||||
<code class="interfacename">CrudRepository</code>. So our
|
||||
<code class="interfacename">UserRepository</code> will now be able to save
|
||||
users, find single ones by id as well as triggering a query to find
|
||||
<code class="interfacename">User</code>s by their email address.</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="repositories.query-methods.details"></a>1.3.2. Defining query methods</h3></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.query-methods.query-lookup-strategies"></a>1.3.2.1. Query lookup strategies</h4></div></div></div><p>The next thing we have to discuss is the definition of query
|
||||
methods. There are two main ways that the repository proxy is able to
|
||||
come up with the store specific query from the method name. The first
|
||||
option is to derive the query from the method name directly, the
|
||||
second is using some kind of additionally created query. What detailed
|
||||
options are available pretty much depends on the actual store,
|
||||
however, there's got to be some algorithm that decides what actual
|
||||
query is created.</p><p>There are three strategies available for the repository
|
||||
infrastructure to resolve the query. The strategy to be used can be
|
||||
configured at the namespace through the
|
||||
<code class="code">query-lookup-strategy</code> attribute. However, It might be the
|
||||
case that some of the strategies are not supported for specific
|
||||
datastores. Here are your options:</p><div class="simplesect" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="d0e240"></a>CREATE</h5></div></div></div><p>This strategy will try to construct a store specific query
|
||||
from the query method's name. The general approach is to remove a
|
||||
given set of well-known prefixes from the method name and parse the
|
||||
rest of the method. Read more about query construction in <a href="#repositories.query-methods.query-creation" title="1.3.2.2. Query creation">Section 1.3.2.2, “Query creation”</a>.</p></div><div class="simplesect" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="d0e247"></a>USE_DECLARED_QUERY</h5></div></div></div><p>This strategy tries to find a declared query which will be
|
||||
used for execution first. The query could be defined by an
|
||||
annotation somewhere or declared by other means. Please consult the
|
||||
documentation of the specific store to find out what options are
|
||||
available for that store. If the repository infrastructure does not
|
||||
find a declared query for the method at bootstrap time it will
|
||||
fail.</p></div><div class="simplesect" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="d0e252"></a>CREATE_IF_NOT_FOUND (default)</h5></div></div></div><p>This strategy is actually a combination of <code class="code">CREATE</code>
|
||||
and <code class="code">USE_DECLARED_QUERY</code>. It will try to lookup a
|
||||
declared query first but create a custom method name based query if
|
||||
no declared query was found. This is the default lookup strategy and
|
||||
thus will be used if you don't configure anything explicitly. It
|
||||
allows quick query definition by method names but also custom tuning
|
||||
of these queries by introducing declared queries as needed.</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.query-methods.query-creation"></a>1.3.2.2. Query creation</h4></div></div></div><p>The query builder mechanism built into Spring Data repository
|
||||
infrastructure is useful to build constraining queries over entities
|
||||
of the repository. We will strip the prefixes <code class="code">findBy</code>,
|
||||
<code class="code">find</code>, <code class="code">readBy</code>, <code class="code">read</code>,
|
||||
<code class="code">getBy</code> as well as <code class="code">get</code> from the method and
|
||||
start parsing the rest of it. At a very basic level you can define
|
||||
conditions on entity properties and concatenate them with
|
||||
<code class="code">AND</code> and <code class="code">OR</code>.</p><div class="example"><a name="d0e292"></a><p class="title"><b>Example 1.4. Query creation from method names</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> PersonRepository <span class="hl-keyword">extends</span> Repository<User, Long> {
|
||||
|
||||
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
|
||||
}</pre></div></div><br class="example-break"><p>The actual result of parsing that method will of course depend
|
||||
on the persistence store we create the query for, however, there are
|
||||
some general things to notice. The expressions are usually property
|
||||
traversals combined with operators that can be concatenated. As you
|
||||
can see in the example you can combine property expressions with And
|
||||
and Or. Beyond that you also get support for various operators like
|
||||
<code class="literal">Between</code>, <code class="literal">LessThan</code>,
|
||||
<code class="literal">GreaterThan</code>, <code class="literal">Like</code> for the
|
||||
property expressions. As the operators supported can vary from
|
||||
datastore to datastore please consult the according part of the
|
||||
reference documentation.</p><div class="section" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="repositories.query-methods.property-expressions"></a>1.3.2.2.1. Property expressions</h5></div></div></div><p>Property expressions can just refer to a direct property of
|
||||
the managed entity (as you just saw in the example above). On query
|
||||
creation time we already make sure that the parsed property is at a
|
||||
property of the managed domain class. However, you can also define
|
||||
constraints by traversing nested properties. Assume
|
||||
<code class="classname">Person</code>s have <code class="classname">Address</code>es
|
||||
with <code class="classname">ZipCode</code>s. In that case a method name
|
||||
of</p><pre class="programlisting">List<Person> findByAddressZipCode(ZipCode zipCode);</pre><p>will create the property traversal
|
||||
<code class="code">x.address.zipCode</code>. The resolution algorithm starts with
|
||||
interpreting the entire part (<code class="literal">AddressZipCode</code>) as
|
||||
property and checks the domain class for a property with that name
|
||||
(uncapitalized). If it succeeds it just uses that. If not it starts
|
||||
splitting up the source at the camel case parts from the right side
|
||||
into a head and a tail and tries to find the according property,
|
||||
e.g. <code class="literal">AddressZip</code> and <code class="literal">Code</code>. If
|
||||
we find a property with that head we take the tail and continue
|
||||
building the tree down from there. As in our case the first split
|
||||
does not match we move the split point to the left
|
||||
(<code class="literal">Address</code>, <code class="literal">ZipCode</code>).</p><p>Although this should work for most cases, there might be cases
|
||||
where the algorithm could select the wrong property. Suppose our
|
||||
<code class="classname">Person</code> class has an <code class="code">addressZip</code>
|
||||
property as well. Then our algorithm would match in the first split
|
||||
round already and essentially choose the wrong property and finally
|
||||
fail (as the type of <code class="classname">addressZip</code> probably has
|
||||
no code property). To resolve this ambiguity you can use
|
||||
<code class="literal">_</code> inside your method name to manually define
|
||||
traversal points. So our method name would end up like so:</p><pre class="programlisting">List<Person> findByAddress_ZipCode(ZipCode zipCode);
|
||||
</pre></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.special-parameters"></a>1.3.2.3. Special parameter handling</h4></div></div></div><p>To hand parameters to your query you simply define method
|
||||
parameters as already seen in the examples above. Besides that we will
|
||||
recognizes certain specific types to apply pagination and sorting to
|
||||
your queries dynamically.</p><div class="example"><a name="d0e369"></a><p class="title"><b>Example 1.5. Using Pageable and Sort in query methods</b></p><div class="example-contents"><pre class="programlisting">Page<User> findByLastname(String lastname, Pageable pageable);
|
||||
|
||||
List<User> findByLastname(String lastname, Sort sort);
|
||||
|
||||
List<User> findByLastname(String lastname, Pageable pageable);</pre></div></div><br class="example-break"><p>The first method allows you to pass a <code class="code">Pageable</code>
|
||||
instance to the query method to dynamically add paging to your
|
||||
statically defined query. <code class="code">Sorting</code> options are handed via
|
||||
the <code class="interfacename">Pageable</code> instance too. If you only
|
||||
need sorting, simply add a <code class="code">Sort</code> parameter to your method.
|
||||
As you also can see, simply returning a
|
||||
<code class="interfacename">List</code> is possible as well. We will then
|
||||
not retrieve the additional metadata required to build the actual
|
||||
<code class="interfacename">Page</code> instance but rather simply
|
||||
restrict the query to lookup only the given range of entities.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/admons/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>To find out how many pages you get for a query entirely we
|
||||
have to trigger an additional count query. This will be derived from
|
||||
the query you actually trigger by default.</p></td></tr></table></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="repositories.create-instances"></a>1.3.3. Creating repository instances</h3></div></div></div><p>So now the question is how to create instances and bean
|
||||
definitions for the repository interfaces defined.</p><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.create-instances.spring"></a>1.3.3.1. XML Configuration</h4></div></div></div><p>The easiest way to do so is by using the Spring namespace that
|
||||
is shipped with each Spring Data module that supports the repository
|
||||
mechanism. Each of those includes a repositories element that allows
|
||||
you to simply define a base package that Spring will scan for
|
||||
you.</p><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans:beans</span> <span class="hl-attribute">xmlns:beans</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/data/jpa"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/data/jpa
|
||||
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repositories"</span> />
|
||||
|
||||
<<span class="hl-tag">/beans:beans</span>></pre><p>In this case we instruct Spring to scan
|
||||
<span class="package">com.acme.repositories</span> and all its sub packages for
|
||||
interfaces extending <code class="interfacename">Repository</code> or one
|
||||
of its sub-interfaces. For each interface found it will register the
|
||||
persistence technology specific
|
||||
<code class="interfacename">FactoryBean</code> to create the according
|
||||
proxies that handle invocations of the query methods. Each of these
|
||||
beans will be registered under a bean name that is derived from the
|
||||
interface name, so an interface of
|
||||
<code class="interfacename">UserRepository</code> would be registered
|
||||
under <code class="code">userRepository</code>. The <code class="code">base-package</code>
|
||||
attribute allows the use of wildcards, so that you can have a pattern
|
||||
of scanned packages.</p><div class="simplesect" lang="en"><div class="titlepage"><div><div><h5 class="title"><a name="d0e429"></a>Using filters</h5></div></div></div><p>By default we will pick up every interface extending the
|
||||
persistence technology specific
|
||||
<code class="interfacename">Repository</code> sub-interface located
|
||||
underneath the configured base package and create a bean instance
|
||||
for it. However, you might want finer grained control over which
|
||||
interfaces bean instances get created for. To do this we support the
|
||||
use of <code class="code"><include-filter /></code> and
|
||||
<code class="code"><exclude-filter /></code> elements inside
|
||||
<code class="code"><repositories /></code>. The semantics are exactly
|
||||
equivalent to the elements in Spring's context namespace. For
|
||||
details see <a xmlns:xlink="http://www.w3.org/1999/xlink" href="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-scanning-filters" target="_top">Spring reference documentation</a> on these
|
||||
elements.</p><p>E.g. to exclude certain interfaces from instantiation as
|
||||
repository, you could use the following configuration:</p><div class="example"><a name="d0e451"></a><p class="title"><b>Example 1.6. Using exclude-filter element</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repositories"</span>>
|
||||
<<span class="hl-tag">context:exclude-filter</span> <span class="hl-attribute">type</span>=<span class="hl-value">"regex"</span> <span class="hl-attribute">expression</span>=<span class="hl-value">".*SomeRepository"</span> />
|
||||
<<span class="hl-tag">/repositories</span>></pre><p>This would exclude all interfaces ending in
|
||||
<code class="interfacename">SomeRepository</code> from being
|
||||
instantiated.</p></div></div><br class="example-break"></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.create-instances.java-config"></a>1.3.3.2. JavaConfig</h4></div></div></div><p>The repository infrastructure can also be triggered using a
|
||||
store-specific
|
||||
<code class="interfacename">@Enable${store}Repositories</code> annotation
|
||||
on a JavaConfig class. For an introduction into Java based
|
||||
configuration of the Spring container please have a look at the
|
||||
reference documentation.<sup>[<a name="d0e469" href="#ftn.d0e469">1</a>]</sup></p><p>A sample configuration to enable Spring Data repositories would
|
||||
look something like this.</p><div class="example"><a name="d0e475"></a><p class="title"><b>Example 1.7. Sample annotation based repository configuration</b></p><div class="example-contents"><pre class="programlisting">@Configuration
|
||||
@EnableJpaRepositories("com.acme.repositories")
|
||||
class ApplicationConfiguration {
|
||||
|
||||
@Bean
|
||||
public EntityManagerFactory entityManagerFactory() {
|
||||
// …
|
||||
}
|
||||
}</pre></div></div><br class="example-break"><p>Note that the sample uses the JPA specific annotation which
|
||||
would have to be exchanged dependingon which store module you actually
|
||||
use. The same applies to the definition of the
|
||||
<code class="interfacename">EntityManagerFactory</code> bean. Please
|
||||
consult the sections covering the store-specific configuration.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="repositories.create-instances.standalone"></a>1.3.3.3. Standalone usage</h4></div></div></div><p>You can also use the repository infrastructure outside of a
|
||||
Spring container usage. You will still need to have some of the Spring
|
||||
libraries on your classpath but you can generally setup repositories
|
||||
programmatically as well. The Spring Data modules providing repository
|
||||
support ship a persistence technology specific
|
||||
<code class="classname">RepositoryFactory</code> that can be used as
|
||||
follows:</p><div class="example"><a name="d0e493"></a><p class="title"><b>Example 1.8. Standalone usage of repository factory</b></p><div class="example-contents"><pre class="programlisting">RepositoryFactorySupport factory = … <span class="hl-comment">// Instantiate factory here</span>
|
||||
UserRepository repository = factory.getRepository(UserRepository.<span class="hl-keyword">class</span>);</pre></div></div><br class="example-break"></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="repositories.custom-implementations"></a>1.4. Custom implementations</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="repositories.single-repository-behaviour"></a>1.4.1. Adding behaviour to single repositories</h3></div></div></div><p>Often it is necessary to provide a custom implementation for a few
|
||||
repository methods. Spring Data repositories easily allow you to provide
|
||||
custom repository code and integrate it with generic CRUD abstraction
|
||||
and query method functionality. To enrich a repository with custom
|
||||
functionality you have to define an interface and an implementation for
|
||||
that functionality first and let the repository interface you provided
|
||||
so far extend that custom interface.</p><div class="example"><a name="d0e506"></a><p class="title"><b>Example 1.9. Interface for custom repository functionality</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">interface</span> UserRepositoryCustom {
|
||||
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> someCustomMethod(User user);
|
||||
}</pre></div></div><br class="example-break"><div class="example"><a name="d0e511"></a><p class="title"><b>Example 1.10. Implementation of custom repository functionality</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">class</span> UserRepositoryImpl <span class="hl-keyword">implements</span> UserRepositoryCustom {
|
||||
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> someCustomMethod(User user) {
|
||||
<span class="hl-comment">// Your custom implementation</span>
|
||||
}
|
||||
}</pre><p>Note that the implementation itself does not depend on
|
||||
Spring Data and can be a regular Spring bean. So you can use standard
|
||||
dependency injection behaviour to inject references to other beans,
|
||||
take part in aspects and so on.</p></div></div><br class="example-break"><div class="example"><a name="d0e518"></a><p class="title"><b>Example 1.11. Changes to the your basic repository interface</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> UserRepository <span class="hl-keyword">extends</span> CrudRepository<User, Long>, UserRepositoryCustom {
|
||||
|
||||
<span class="hl-comment">// Declare query methods here</span>
|
||||
}</pre><p>Let your standard repository interface extend the custom
|
||||
one. This makes CRUD and custom functionality available to
|
||||
clients.</p></div></div><br class="example-break"><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e525"></a>Configuration</h4></div></div></div><p>If you use namespace configuration the repository infrastructure
|
||||
tries to autodetect custom implementations by looking up classes in
|
||||
the package we found a repository using the naming conventions
|
||||
appending the namespace element's attribute
|
||||
<code class="code">repository-impl-postfix</code> to the classname. This suffix
|
||||
defaults to <code class="code">Impl</code>.</p><div class="example"><a name="d0e536"></a><p class="title"><b>Example 1.12. Configuration example</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repository"</span> />
|
||||
|
||||
<<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repository"</span> <span class="hl-attribute">repository-impl-postfix</span>=<span class="hl-value">"FooBar"</span> /></pre></div></div><br class="example-break"><p>The first configuration example will try to lookup a class
|
||||
<code class="classname">com.acme.repository.UserRepositoryImpl</code> to act
|
||||
as custom repository implementation, where the second example will try
|
||||
to lookup
|
||||
<code class="classname">com.acme.repository.UserRepositoryFooBar</code>.</p></div><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e550"></a>Manual wiring</h4></div></div></div><p>The approach above works perfectly well if your custom
|
||||
implementation uses annotation based configuration and autowiring
|
||||
entirely as it will be treated as any other Spring bean. If your
|
||||
custom implementation bean needs some special wiring you simply
|
||||
declare the bean and name it after the conventions just described. We
|
||||
will then pick up the custom bean by name rather than creating an
|
||||
instance.</p><div class="example"><a name="d0e555"></a><p class="title"><b>Example 1.13. Manual wiring of custom implementations (I)</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repository"</span> />
|
||||
|
||||
<<span class="hl-tag">beans:bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"userRepositoryImpl"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"…"</span>>
|
||||
<<span class="hl-comment">!-- further configuration --</span>>
|
||||
<<span class="hl-tag">/beans:bean</span>></pre></div></div><br class="example-break"></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="repositories.custom-behaviour-for-all-repositories"></a>1.4.2. Adding custom behaviour to all repositories</h3></div></div></div><p>In other cases you might want to add a single method to all of
|
||||
your repository interfaces. So the approach just shown is not feasible.
|
||||
The first step to achieve this is adding and intermediate interface to
|
||||
declare the shared behaviour</p><div class="example"><a name="d0e565"></a><p class="title"><b>Example 1.14. An interface declaring custom shared behaviour</b></p><div class="example-contents"><pre class="programlisting">
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> MyRepository<T, ID <span class="hl-keyword">extends</span> Serializable>
|
||||
<span class="hl-keyword">extends</span> JpaRepository<T, ID> {
|
||||
|
||||
<span class="hl-keyword">void</span> sharedCustomMethod(ID id);
|
||||
}</pre></div></div><br class="example-break"><p>Now your individual repository interfaces will extend this
|
||||
intermediate interface instead of the
|
||||
<code class="interfacename">Repository</code> interface to include the
|
||||
functionality declared. The second step is to create an implementation
|
||||
of this interface that extends the persistence technology specific
|
||||
repository base class which will then act as a custom base class for the
|
||||
repository proxies.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/admons/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The default behaviour of the Spring <code class="code"><repositories
|
||||
/></code> namespace is to provide an implementation for all
|
||||
interfaces that fall under the <code class="code">base-package</code>. This means
|
||||
that if left in it's current state, an implementation instance of
|
||||
<code class="interfacename">MyRepository</code> will be created by Spring.
|
||||
This is of course not desired as it is just supposed to act as an
|
||||
intermediary between <code class="interfacename">Repository</code> and the
|
||||
actual repository interfaces you want to define for each entity. To
|
||||
exclude an interface extending
|
||||
<code class="interfacename">Repository</code> from being instantiated as a
|
||||
repository instance it can either be annotate it with
|
||||
<code class="interfacename">@NoRepositoryBean</code> or moved out side of
|
||||
the configured <code class="code">base-package</code>.</p></td></tr></table></div><div class="example"><a name="d0e600"></a><p class="title"><b>Example 1.15. Custom repository base class</b></p><div class="example-contents"><pre class="programlisting">
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> MyRepositoryImpl<T, ID <span class="hl-keyword">extends</span> Serializable>
|
||||
<span class="hl-keyword">extends</span> SimpleJpaRepository<T, ID> <span class="hl-keyword">implements</span> MyRepository<T, ID> {
|
||||
|
||||
<span class="hl-keyword">private</span> EntityManager entityManager;
|
||||
|
||||
<span class="hl-comment">// There are two constructors to choose from, either can be used.</span>
|
||||
<span class="hl-keyword">public</span> MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
|
||||
<span class="hl-keyword">super</span>(domainClass, entityManager);
|
||||
|
||||
<span class="hl-comment">// This is the recommended method for accessing inherited class dependencies.</span>
|
||||
<span class="hl-keyword">this</span>.entityManager = entityManager;
|
||||
}
|
||||
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> sharedCustomMethod(ID id) {
|
||||
<span class="hl-comment">// implementation goes here</span>
|
||||
}
|
||||
}</pre></div></div><br class="example-break"><p>The last step is to create a custom repository factory to replace
|
||||
the default <code class="classname">RepositoryFactoryBean</code> that will in
|
||||
turn produce a custom <code class="classname">RepositoryFactory</code>. The new
|
||||
repository factory will then provide your
|
||||
<code class="classname">MyRepositoryImpl</code> as the implementation of any
|
||||
interfaces that extend the <code class="interfacename">Repository</code>
|
||||
interface, replacing the <code class="classname">SimpleJpaRepository</code>
|
||||
implementation you just extended.</p><div class="example"><a name="d0e622"></a><p class="title"><b>Example 1.16. Custom repository factory bean</b></p><div class="example-contents"><pre class="programlisting">
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> MyRepositoryFactoryBean<R <span class="hl-keyword">extends</span> JpaRepository<T, I>, T, I <span class="hl-keyword">extends</span> Serializable>
|
||||
<span class="hl-keyword">extends</span> JpaRepositoryFactoryBean<R, T, I> {
|
||||
|
||||
<span class="hl-keyword">protected</span> RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
|
||||
|
||||
<span class="hl-keyword">return</span> <span class="hl-keyword">new</span> MyRepositoryFactory(entityManager);
|
||||
}
|
||||
|
||||
<span class="hl-keyword">private</span> <span class="hl-keyword">static</span> <span class="hl-keyword">class</span> MyRepositoryFactory<T, I <span class="hl-keyword">extends</span> Serializable> <span class="hl-keyword">extends</span> JpaRepositoryFactory {
|
||||
|
||||
<span class="hl-keyword">private</span> EntityManager entityManager;
|
||||
|
||||
<span class="hl-keyword">public</span> MyRepositoryFactory(EntityManager entityManager) {
|
||||
<span class="hl-keyword">super</span>(entityManager);
|
||||
|
||||
<span class="hl-keyword">this</span>.entityManager = entityManager;
|
||||
}
|
||||
|
||||
<span class="hl-keyword">protected</span> Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
<span class="hl-keyword">return</span> <span class="hl-keyword">new</span> MyRepositoryImpl<T, I>((Class<T>) metadata.getDomainClass(), entityManager);
|
||||
}
|
||||
|
||||
<span class="hl-keyword">protected</span> Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
|
||||
<span class="hl-comment">// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory</span>
|
||||
<span class="hl-comment">//to check for QueryDslJpaRepository's which is out of scope.</span>
|
||||
<span class="hl-keyword">return</span> MyRepository.<span class="hl-keyword">class</span>;
|
||||
}
|
||||
}
|
||||
}</pre></div></div><br class="example-break"><p>Finally you can either declare beans of the custom factory
|
||||
directly or use the <code class="code">factory-class</code> attribute of the Spring
|
||||
namespace to tell the repository infrastructure to use your custom
|
||||
factory implementation.</p><div class="example"><a name="d0e632"></a><p class="title"><b>Example 1.17. Using the custom factory with the namespace</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repository"</span>
|
||||
<span class="hl-attribute">factory-class</span>=<span class="hl-value">"com.acme.MyRepositoryFactoryBean"</span> /></pre></div></div><br class="example-break"></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e637"></a>1.5. Extensions</h2></div></div></div><p>This chapter documents a set of Spring Data extensions that enable
|
||||
Spring Data usage in a variety of contexts. Currently most of the
|
||||
integration is targeted towards Spring MVC.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="web-domain-class-binding"></a>1.5.1. Domain class web binding for Spring MVC</h3></div></div></div><p>Given you are developing a Spring MVC web applications you
|
||||
typically have to resolve domain class ids from URLs. By default it's
|
||||
your task to transform that request parameter or URL part into the
|
||||
domain class to hand it layers below then or execute business logic on
|
||||
the entities directly. This should look something like this:</p><pre class="programlisting">@Controller
|
||||
@RequestMapping(<span class="hl-string">"/users"</span>)
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> UserController {
|
||||
|
||||
<span class="hl-keyword">private</span> <span class="hl-keyword">final</span> UserRepository userRepository;
|
||||
|
||||
<span class="hl-keyword">public</span> UserController(UserRepository userRepository) {
|
||||
userRepository = userRepository;
|
||||
}
|
||||
|
||||
@RequestMapping(<span class="hl-string">"/{id}"</span>)
|
||||
<span class="hl-keyword">public</span> String showUserForm(@PathVariable(<span class="hl-string">"id"</span>) Long id, Model model) {
|
||||
|
||||
<span class="hl-comment">// Do null check for id</span>
|
||||
User user = userRepository.findOne(id);
|
||||
<span class="hl-comment">// Do null check for user</span>
|
||||
<span class="hl-comment">// Populate model</span>
|
||||
<span class="hl-keyword">return</span> <span class="hl-string">"user"</span>;
|
||||
}
|
||||
}</pre><p>First you pretty much have to declare a repository dependency for
|
||||
each controller to lookup the entity managed by the controller or
|
||||
repository respectively. Beyond that looking up the entity is
|
||||
boilerplate as well as it's always a <code class="methodname">findOne(…)</code>
|
||||
call. Fortunately Spring provides means to register custom converting
|
||||
components that allow conversion between a <code class="classname">String</code>
|
||||
value to an arbitrary type.</p><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e657"></a>PropertyEditors</h4></div></div></div><p>For versions up to Spring 3.0 simple Java
|
||||
<code class="interfacename">PropertyEditor</code>s had to be used. Thus,
|
||||
we offer a <code class="classname">DomainClassPropertyEditorRegistrar</code>,
|
||||
that will look up all Spring Data repositories registered in the
|
||||
<code class="interfacename">ApplicationContext</code> and register a
|
||||
custom <code class="interfacename">PropertyEditor</code> for the managed
|
||||
domain class</p><pre class="programlisting"><<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"</span>>
|
||||
<<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"webBindingInitializer"</span>>
|
||||
<<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"….web.bind.support.ConfigurableWebBindingInitializer"</span>>
|
||||
<<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"propertyEditorRegistrars"</span>>
|
||||
<<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar"</span> />
|
||||
<<span class="hl-tag">/property</span>>
|
||||
<<span class="hl-tag">/bean</span>>
|
||||
<<span class="hl-tag">/property</span>>
|
||||
<<span class="hl-tag">/bean</span>></pre><p>If you have configured Spring MVC like this you can turn your
|
||||
controller into the following that reduces a lot of the clutter and
|
||||
boilerplate.</p><pre class="programlisting">@Controller
|
||||
@RequestMapping(<span class="hl-string">"/users"</span>)
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> UserController {
|
||||
|
||||
@RequestMapping(<span class="hl-string">"/{id}"</span>)
|
||||
<span class="hl-keyword">public</span> String showUserForm(@PathVariable(<span class="hl-string">"id"</span>) User user, Model model) {
|
||||
|
||||
<span class="hl-comment">// Do null check for user</span>
|
||||
<span class="hl-comment">// Populate model</span>
|
||||
<span class="hl-keyword">return</span> <span class="hl-string">"userForm"</span>;
|
||||
}
|
||||
}</pre></div><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e680"></a>ConversionService</h4></div></div></div><p>As of Spring 3.0 the
|
||||
<code class="interfacename">PropertyEditor</code> support is superseeded
|
||||
by a new conversion infrstructure that leaves all the drawbacks of
|
||||
<code class="interfacename">PropertyEditor</code>s behind and uses a
|
||||
stateless X to Y conversion approach. We now ship with a
|
||||
<code class="classname">DomainClassConverter</code> that pretty much mimics
|
||||
the behaviour of
|
||||
<code class="classname">DomainClassPropertyEditorRegistrar</code>. To register
|
||||
the converter you have to declare
|
||||
<code class="classname">ConversionServiceFactoryBean</code>, register the
|
||||
converter and tell the Spring MVC namespace to use the configured
|
||||
conversion service:</p><pre class="programlisting"><<span class="hl-tag">mvc:annotation-driven</span> <span class="hl-attribute">conversion-service</span>=<span class="hl-value">"conversionService"</span> />
|
||||
|
||||
<<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"conversionService"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"….context.support.ConversionServiceFactoryBean"</span>>
|
||||
<<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"converters"</span>>
|
||||
<<span class="hl-tag">list</span>>
|
||||
<<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.data.repository.support.DomainClassConverter"</span>>
|
||||
<<span class="hl-tag">constructor-arg</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"conversionService"</span> />
|
||||
<<span class="hl-tag">/bean</span>>
|
||||
<<span class="hl-tag">/list</span>>
|
||||
<<span class="hl-tag">/property</span>>
|
||||
<<span class="hl-tag">/bean</span>></pre></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="web-pagination"></a>1.5.2. Web pagination</h3></div></div></div><pre class="programlisting">@Controller
|
||||
@RequestMapping(<span class="hl-string">"/users"</span>)
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> UserController {
|
||||
|
||||
<span class="hl-comment">// DI code omitted</span>
|
||||
|
||||
@RequestMapping
|
||||
<span class="hl-keyword">public</span> String showUsers(Model model, HttpServletRequest request) {
|
||||
|
||||
<span class="hl-keyword">int</span> page = Integer.parseInt(request.getParameter(<span class="hl-string">"page"</span>));
|
||||
<span class="hl-keyword">int</span> pageSize = Integer.parseInt(request.getParameter(<span class="hl-string">"pageSize"</span>));
|
||||
model.addAttribute(<span class="hl-string">"users"</span>, userService.getUsers(pageable));
|
||||
<span class="hl-keyword">return</span> <span class="hl-string">"users"</span>;
|
||||
}
|
||||
}</pre><p>As you can see the naive approach requires the method to contain
|
||||
an <code class="interfacename">HttpServletRequest</code> parameter that has
|
||||
to be parsed manually. We even omitted an appropriate failure handling
|
||||
which would make the code even more verbose. The bottom line is that the
|
||||
controller actually shouldn't have to handle the functionality of
|
||||
extracting pagination information from the request. So we include a
|
||||
<code class="classname">PageableArgumentResolver</code> that will do the work
|
||||
for you.</p><pre class="programlisting"><<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"</span>>
|
||||
<<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"customArgumentResolvers"</span>>
|
||||
<<span class="hl-tag">list</span>>
|
||||
<<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.data.web.PageableArgumentResolver"</span> />
|
||||
<<span class="hl-tag">/list</span>>
|
||||
<<span class="hl-tag">/property</span>>
|
||||
<<span class="hl-tag">/bean</span>></pre><p>This configuration allows you to simplify controllers down to
|
||||
something like this:</p><pre class="programlisting">@Controller
|
||||
@RequestMapping(<span class="hl-string">"/users"</span>)
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> UserController {
|
||||
|
||||
@RequestMapping
|
||||
<span class="hl-keyword">public</span> String showUsers(Model model, Pageable pageable) {
|
||||
|
||||
model.addAttribute(<span class="hl-string">"users"</span>, userDao.readAll(pageable));
|
||||
<span class="hl-keyword">return</span> <span class="hl-string">"users"</span>;
|
||||
}
|
||||
}</pre><p>The <code class="classname">PageableArgumentResolver</code> will
|
||||
automatically resolve request parameters to build a
|
||||
<code class="classname">PageRequest</code> instance. By default it will expect
|
||||
the following structure for the request parameters:</p><div class="table"><a name="d0e729"></a><p class="title"><b>Table 1.1. Request parameters evaluated by
|
||||
<code class="classname">PageableArgumentResolver</code></b></p><div class="table-contents"><table summary="Request parameters evaluated by
 PageableArgumentResolver" border="1"><colgroup><col><col></colgroup><tbody><tr><td><code class="code">page</code></td><td>The page you want to retrieve</td></tr><tr><td><code class="code">page.size</code></td><td>The size of the page you want to retrieve</td></tr><tr><td><code class="code">page.sort</code></td><td>The property that should be sorted by</td></tr><tr><td><code class="code">page.sort.dir</code></td><td>The direction that should be used for sorting</td></tr></tbody></table></div></div><br class="table-break"><p>In case you need multiple <code class="interfacename">Pageable</code>s
|
||||
to be resolved from the request (for multiple tables e.g.) you can use
|
||||
Spring's <code class="interfacename">@Qualifier</code> annotation to
|
||||
distinguish one from another. The request parameters then have to be
|
||||
prefixed with <code class="code">${qualifier}_</code>. So a method signature like
|
||||
this:</p><pre class="programlisting"><span class="hl-keyword">public</span> String showUsers(Model model,
|
||||
@Qualifier(<span class="hl-string">"foo"</span>) Pageable first,
|
||||
@Qualifier(<span class="hl-string">"bar"</span>) Pageable second) { … }
|
||||
</pre><p>you'd have to populate <code class="code">foo_page</code> and
|
||||
<code class="code">bar_page</code> and the according subproperties.</p><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e783"></a>Defaulting</h4></div></div></div><p>The <code class="classname">PageableArgumentResolver</code> will use a
|
||||
<code class="classname">PageRequest</code> with the first page and a page size
|
||||
of 10 by default and will use that in case it can't resolve a
|
||||
<code class="classname">PageRequest</code> from the request (because of
|
||||
missing parameters e.g.). You can configure a global default on the
|
||||
bean declaration directly. In case you might need controller method
|
||||
specific defaults for the <code class="interfacename">Pageable</code>
|
||||
simply annotate the method parameter with
|
||||
<code class="interfacename">@PageableDefaults</code> and specify page and
|
||||
page size as annotation attributes:</p><pre class="programlisting"><span class="hl-keyword">public</span> String showUsers(Model model,
|
||||
@PageableDefaults(pageNumber = 0, value = 30) Pageable pageable) { … }
|
||||
</pre></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e805"></a>1.5.3. Repository populators</h3></div></div></div><p>If you have been working with the JDBC module of Spring you're
|
||||
probably familiar with the support to populate a DataSource using SQL
|
||||
scripts. A similar abstraction is available on the repositories level
|
||||
although we don't use SQL as data definition language as we need to be
|
||||
store independent of course. Thus the populators support XML (through
|
||||
Spring's OXM abstraction) and JSON (through Jackson) to define data for
|
||||
the repositories to be populated with.</p><p>Assume you have a file <code class="filename">data.json</code> with the
|
||||
following content:</p><div class="example"><a name="d0e815"></a><p class="title"><b>Example 1.18. Data defined in JSON</b></p><div class="example-contents"><pre class="programlisting">[ { "_class" : "com.acme.Person",
|
||||
"firstname" : "Dave",
|
||||
"lastname" : "Matthews" },
|
||||
{ "_class" : "com.acme.Person",
|
||||
"firstname" : "Carter",
|
||||
"lastname" : "Beauford" } ]</pre></div></div><br class="example-break"><p>You can easily populate you repositories by using the populator
|
||||
elements of the repository namespace provided in Spring Data Commons. To
|
||||
get the just shown data be populated to your
|
||||
<code class="interfacename">PersonRepository</code> all you need to do is
|
||||
the following:</p><div class="example"><a name="d0e825"></a><p class="title"><b>Example 1.19. Declaring a Jackson repository populator</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns:repository</span>=<span class="hl-value">"http://www.springframework.org/schema/data/repository"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/data/repository
|
||||
http://www.springframework.org/schema/data/repository/spring-repository.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">repository:jackson-populator</span> <span class="hl-attribute">location</span>=<span class="hl-value">"classpath:data.json"</span> />
|
||||
|
||||
<<span class="hl-tag">/beans</span>></pre></div></div><br class="example-break"><p>This declaration causes the data.json file being read,
|
||||
deserialized by a Jackson <code class="classname">ObjectMapper</code>. The type
|
||||
the JSON object will be unmarshalled to will be determined by inspecting
|
||||
the <code class="code">_class</code> attribute of the JSON document. We will
|
||||
eventually select the appropriate repository being able to handle the
|
||||
object just deserialized.</p><p>To rather use XML to define the repositories shall be populated
|
||||
with you can use the unmarshaller-populator you hand one of the
|
||||
marshaller options Spring OXM provides you with.</p><div class="example"><a name="d0e840"></a><p class="title"><b>Example 1.20. Declaring an unmarshalling repository populator (using
|
||||
JAXB)</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns:repository</span>=<span class="hl-value">"http://www.springframework.org/schema/data/repository"</span>
|
||||
<span class="hl-attribute">xmlns:oxm</span>=<span class="hl-value">"http://www.springframework.org/schema/oxm"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/data/repository
|
||||
http://www.springframework.org/schema/data/repository/spring-repository.xsd
|
||||
http://www.springframework.org/schema/oxm
|
||||
http://www.springframework.org/schema/oxm/spring-oxm.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">repository:unmarshaller-populator</span> <span class="hl-attribute">location</span>=<span class="hl-value">"classpath:data.json"</span> <span class="hl-attribute">unmarshaller-ref</span>=<span class="hl-value">"unmarshaller"</span> />
|
||||
|
||||
<<span class="hl-tag">oxm:jaxb2-marshaller</span> <span class="hl-attribute">contextPath</span>=<span class="hl-value">"com.acme"</span> />
|
||||
|
||||
<<span class="hl-tag">/beans</span>></pre></div></div><br class="example-break"></div></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.d0e469" href="#d0e469">1</a>] </sup>JavaConfig in the Spring reference documentation - <a xmlns:xlink="http://www.w3.org/1999/xlink" href="http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java" target="_top">http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java</a></p></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="elasticsearch.repositories"></a>Chapter 2. Elasticsearch Repositories</h2></div></div></div><div class="abstract"><p class="title"><b>Abstract</b></p><p>This chapter includes details of the Elasticsearch repository
|
||||
implementation.
|
||||
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="elasticsearch.introduction"></a>2.1. Introduction</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.namespace"></a>2.1.1. Spring Namespace</h3></div></div></div><p>
|
||||
The Spring Data Elasticsearch module contains a custom namespace allowing
|
||||
definition of repository beans as well as elements for instantiating
|
||||
a
|
||||
<code class="classname">ElasticsearchServer</code>
|
||||
.
|
||||
</p><p>
|
||||
Using the
|
||||
<code class="code">repositories</code>
|
||||
element looks up Spring Data repositories as described in
|
||||
<a href="#repositories.create-instances" title="1.3.3. Creating repository instances">Section 1.3.3, “Creating repository instances”</a>
|
||||
.
|
||||
</p><div class="example"><a name="d0e869"></a><p class="title"><b>Example 2.1. Setting up Elasticsearch repositories using Namespace</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns:elasticsearch</span>=<span class="hl-value">"http://www.springframework.org/schema/data/elasticsearch"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">elasticsearch:repositories</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"com.acme.repositories"</span> />
|
||||
<<span class="hl-tag">/beans</span>></pre></div></div><br class="example-break"><p>
|
||||
Using the
|
||||
<code class="code">Transport Client</code>
|
||||
or
|
||||
<code class="code">Node Client</code>
|
||||
element registers an instance of
|
||||
<code class="code">Elasticsearch Server</code>
|
||||
in the context.
|
||||
|
||||
</p><div class="example"><a name="d0e885"></a><p class="title"><b>Example 2.2. Transport Client using Namespace</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns:elasticsearch</span>=<span class="hl-value">"http://www.springframework.org/schema/data/elasticsearch"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">elasticsearch:transport-client</span> <span class="hl-attribute">id</span>=<span class="hl-value">"client"</span> <span class="hl-attribute">cluster-nodes</span>=<span class="hl-value">"localhost:9300,someip:9300"</span> />
|
||||
<<span class="hl-tag">/beans</span>> </pre></div></div><p><br class="example-break">
|
||||
|
||||
</p><div class="example"><a name="d0e891"></a><p class="title"><b>Example 2.3. Node Client using Namespace</b></p><div class="example-contents"><pre class="programlisting"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>>
|
||||
<<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
|
||||
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span class="hl-attribute">xmlns:elasticsearch</span>=<span class="hl-value">"http://www.springframework.org/schema/data/elasticsearch"</span>
|
||||
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd"</span>>
|
||||
|
||||
<<span class="hl-tag">elasticsearch:node-client</span> <span class="hl-attribute">id</span>=<span class="hl-value">"client"</span> <span class="hl-attribute">local</span>=<span class="hl-value">"true"</span><span class="hl-attribute">"</span> />
|
||||
<<span class="hl-tag">/beans</span>> </pre></div></div><p><br class="example-break">
|
||||
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.annotation"></a>2.1.2. Annotation based configuration</h3></div></div></div><p>The Spring Data Elasticsearch repositories support cannot only be
|
||||
activated through an XML namespace but also using an annotation
|
||||
through JavaConfig.
|
||||
</p><div class="example"><a name="d0e902"></a><p class="title"><b>Example 2.4. Spring Data Elasticsearch repositories using JavaConfig</b></p><div class="example-contents"><pre class="programlisting">
|
||||
@Configuration
|
||||
@EnableElasticsearchRepositories(basePackages = <span class="hl-string">"org/springframework/data/elasticsearch/repositories"</span>)
|
||||
<span class="hl-keyword">static</span> <span class="hl-keyword">class</span> Config {
|
||||
|
||||
@Bean
|
||||
<span class="hl-keyword">public</span> ElasticsearchOperations elasticsearchTemplate() {
|
||||
<span class="hl-keyword">return</span> <span class="hl-keyword">new</span> ElasticsearchTemplate(nodeBuilder().local(true).node().client());
|
||||
}
|
||||
}</pre><p>
|
||||
The configuration above sets up an
|
||||
<code class="classname">Embedded Elasticsearch Server</code>
|
||||
which is used by the
|
||||
<code class="classname">ElasticsearchTemplate</code>
|
||||
. Spring Data Elasticsearch Repositories are activated using the
|
||||
<code class="interfacename">@EnableElasticsearchRepositories</code>
|
||||
annotation, which
|
||||
essentially carries the same attributes as the XML
|
||||
namespace does. If no
|
||||
base package is configured, it will use the
|
||||
one
|
||||
the configuration class
|
||||
resides in.
|
||||
</p></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.cdi"></a>2.1.3. Elasticsearch Repositores using CDI</h3></div></div></div><p>The Spring Data Elasticsearch repositories can also be set up using CDI
|
||||
functionality.
|
||||
</p><div class="example"><a name="d0e923"></a><p class="title"><b>Example 2.5. Spring Data Elasticsearch repositories using JavaConfig</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">class</span> ElasticsearchTemplateProducer {
|
||||
|
||||
@Produces
|
||||
@ApplicationScoped
|
||||
<span class="hl-keyword">public</span> ElasticsearchOperations createElasticsearchTemplate() {
|
||||
<span class="hl-keyword">return</span> <span class="hl-keyword">new</span> ElasticsearchTemplate(<span class="hl-keyword">new</span> EmbeddedElasticsearchServerFactory(<span class="hl-string">"classpath:com/acme/Elasticsearch"</span>));
|
||||
}
|
||||
}
|
||||
|
||||
<span class="hl-keyword">class</span> ProductService {
|
||||
|
||||
<span class="hl-keyword">private</span> ProductRepository repository;
|
||||
|
||||
<span class="hl-keyword">public</span> Page<Product> findAvailableBookByName(String name, Pageable pageable) {
|
||||
<span class="hl-keyword">return</span> repository.findByAvailableTrueAndNameStartingWith(name, pageable);
|
||||
}
|
||||
|
||||
@Inject
|
||||
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> setRepository(ProductRepository repository) {
|
||||
<span class="hl-keyword">this</span>.repository = repository;
|
||||
}
|
||||
}</pre></div></div><br class="example-break"></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="elasticsearch.query-methods"></a>2.2. Query methods</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.query-methods.finders"></a>2.2.1. Query lookup strategies</h3></div></div></div><p>
|
||||
The Elasticsearch module supports all basic query building feature as String,Abstract,Criteria or
|
||||
have
|
||||
it being derived from the method name.
|
||||
</p><div class="simplesect" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e936"></a>Declared queries</h4></div></div></div><p>
|
||||
Deriving the query from the method name is not always sufficient
|
||||
and/or may result in unreadable method names. In this case one
|
||||
might make either use of
|
||||
<code class="interfacename">@Query</code>
|
||||
annotation (see
|
||||
<a href="#elasticsearch.query-methods.at-query" title="2.2.3. Using @Query Annotation">Section 2.2.3, “Using @Query Annotation”</a>
|
||||
).
|
||||
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.query-methods.criterions"></a>2.2.2. Query creation</h3></div></div></div><p>
|
||||
Generally the query creation mechanism for Elasticsearch works as described
|
||||
in
|
||||
<a href="#repositories.query-methods" title="1.3. Query methods">Section 1.3, “Query methods”</a>
|
||||
. Here's a short example
|
||||
of what a Elasticsearch query method translates into:
|
||||
</p><div class="example"><a name="d0e953"></a><p class="title"><b>Example 2.6. Query creation from method names</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> BookRepository <span class="hl-keyword">extends</span> Repository<Book, String> {
|
||||
List<Book> findByNameAndPrice(String name, Integer price);
|
||||
}</pre><p>
|
||||
The method name above will be translated into the following
|
||||
Elasticsearch json query
|
||||
</p><pre class="programlisting">
|
||||
{ "bool" :
|
||||
{ "must" :
|
||||
[
|
||||
{ "field" : {"name" : "?"} },
|
||||
{ "field" : {"price" : "?"} }
|
||||
] } }</pre></div></div><p><br class="example-break">
|
||||
</p><p>
|
||||
A list of supported keywords for Elasticsearch is shown below.
|
||||
</p><div class="table"><a name="d0e965"></a><p class="title"><b>Table 2.1. Supported keywords inside method names</b></p><div class="table-contents"><table summary="Supported keywords inside method names" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>Keyword</th><th>Sample</th><th>Elasticsearch Query String</th></tr></thead><tbody><tr><td>
|
||||
<code class="code">And</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameAndPrice</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Or</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameOrPrice</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Is</code>
|
||||
</td><td>
|
||||
<code class="code">findByName</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"field" : {"name" : "?"}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Not</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameNot</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Between</code>
|
||||
</td><td>
|
||||
<code class="code">findByPriceBetween</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">LessThanEqual</code>
|
||||
</td><td>
|
||||
<code class="code">findByPriceLessThan</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">GreaterThanEqual</code>
|
||||
</td><td>
|
||||
<code class="code">findByPriceGreaterThan</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Before</code>
|
||||
</td><td>
|
||||
<code class="code">findByPriceBefore</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">After</code>
|
||||
</td><td>
|
||||
<code class="code">findByPriceAfter</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Like</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameLike</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">StartingWith</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameStartingWith</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">EndingWith</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameEndingWith</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Contains/Containing</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameContaining</code>
|
||||
</td><td>
|
||||
<code class="code">{"bool" : {"must" : {"field" : {"name" : {"query" : "*?*","analyze_wildcard" : true}}}}}</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">In</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameIn(Collection<String>
|
||||
names)
|
||||
</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">NotIn</code>
|
||||
</td><td>
|
||||
<code class="code">findByNameNotIn(Collection<String>
|
||||
names)
|
||||
</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">Near</code>
|
||||
</td><td>
|
||||
<code class="code">findByStoreNear</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !
|
||||
</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">True</code>
|
||||
</td><td>
|
||||
<code class="code">findByAvailableTrue</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">False</code>
|
||||
</td><td>
|
||||
<code class="code">findByAvailableFalse</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !</code>
|
||||
</td></tr><tr><td>
|
||||
<code class="code">OrderBy</code>
|
||||
</td><td>
|
||||
<code class="code">findByAvailableTrueOrderByNameDesc</code>
|
||||
</td><td>
|
||||
<code class="code">Not Supported Yet !</code>
|
||||
</td></tr></tbody></table></div></div><p><br class="table-break">
|
||||
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="elasticsearch.query-methods.at-query"></a>2.2.3. Using @Query Annotation</h3></div></div></div><div class="example"><a name="d0e1289"></a><p class="title"><b>Example 2.7.
|
||||
Declare query at the method using the
|
||||
<code class="interfacename">@Query</code>
|
||||
annotation.
|
||||
</b></p><div class="example-contents"><pre class="programlisting"><span class="hl-keyword">public</span> <span class="hl-keyword">interface</span> BookRepository <span class="hl-keyword">extends</span> ElasticsearchRepository<Book, String> {
|
||||
@Query(<span class="hl-string">"{"</span>bool" : {<span class="hl-string">"must"</span> : {<span class="hl-string">"field"</span> : {<span class="hl-string">"name"</span> : <span class="hl-string">"?0"</span>}}}}<span class="hl-string">")
|
||||
Page<Book> findByName(String name,Pageable pageable);
|
||||
}</span></pre></div></div><br class="example-break"></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="elasticsearch.misc"></a>Chapter 3. Miscellaneous Elasticsearch Operation Support</h2></div></div></div><div class="abstract"><p class="title"><b>Abstract</b></p><p>
|
||||
This chapter covers additional support for Elasticsearch operations
|
||||
that cannot be directly accessed via the repository
|
||||
interface.
|
||||
It is recommended to add those operations as custom
|
||||
implementation as
|
||||
described in
|
||||
<a href="#repositories.custom-implementations" title="1.4. Custom implementations">Section 1.4, “Custom implementations”</a>
|
||||
.
|
||||
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="elasticsearch.misc.filter"></a>3.1. Filter Builder</h2></div></div></div><p>
|
||||
Filter Builder improves query speed.
|
||||
</p><div class="example"><a name="d0e1329"></a><p class="title"><b>Example 3.1. </b></p><div class="example-contents"><pre class="programlisting">
|
||||
<span class="hl-keyword">private</span> ElasticsearchTemplate elasticsearchTemplate;
|
||||
SearchQuery searchQuery = <span class="hl-keyword">new</span> SearchQuery();
|
||||
searchQuery.setElasticsearchQuery(matchAllQuery());
|
||||
searchQuery.setElasticsearchFilter(boolFilter().must(termFilter(<span class="hl-string">"id"</span>, documentId)));
|
||||
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.<span class="hl-keyword">class</span>);
|
||||
</pre></div></div><br class="example-break"></div></div></div><div class="part" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="appendix"></a>Part II. Appendix</h1></div></div></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="namespace-reference"></a>Appendix A. Namespace reference</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="namespace-dao-config"></a>A.1. The <code class="code"><repositories /></code> element</h2></div></div></div><p>The <code class="code"><repositories /></code> triggers the setup of the
|
||||
Spring Data repository infrastructure. The most important attribute is
|
||||
<code class="code">base-package</code> which defines the package to scan for Spring
|
||||
Data repository interfaces.<sup>[<a name="d0e1352" href="#ftn.d0e1352">2</a>]</sup></p><div class="table"><a name="d0e1356"></a><p class="title"><b>Table A.1. Attributes</b></p><div class="table-contents"><table summary="Attributes" border="1"><colgroup><col><col></colgroup><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td><code class="code">base-package</code></td><td>Defines the package to be used to be scanned for repository
|
||||
interfaces extending <code class="interfacename">*Repository</code>
|
||||
(actual interface is determined by specific Spring Data module) in
|
||||
auto detection mode. All packages below the configured package
|
||||
will be scanned, too. Wildcards are also allowed.</td></tr><tr><td><code class="code">repository-impl-postfix</code></td><td>Defines the postfix to autodetect custom repository
|
||||
implementations. Classes whose names end with the configured
|
||||
postfix will be considered as candidates. Defaults to
|
||||
<code class="code">Impl</code>.</td></tr><tr><td><code class="code">query-lookup-strategy</code></td><td>Determines the strategy to be used to create finder
|
||||
queries. See <a href="#repositories.query-methods.query-lookup-strategies" title="1.3.2.1. Query lookup strategies">Section 1.3.2.1, “Query lookup strategies”</a> for
|
||||
details. Defaults to <code class="code">create-if-not-found</code>.</td></tr></tbody></table></div></div><br class="table-break"></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.d0e1352" href="#d0e1352">2</a>] </sup>see <a href="#repositories.create-instances.spring" title="1.3.3.1. XML Configuration">Section 1.3.3.1, “XML Configuration”</a></p></div></div></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="repository-query-keywords"></a>Appendix B. Repository query keywords</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e1401"></a>B.1. Supported query keywords</h2></div></div></div><p>The following table lists the keywords generally supported by the
|
||||
Spring data repository query derivation mechanism. However consult the
|
||||
store specific documentation for the exact list of supported keywords as
|
||||
some of the ones listed here might not be supported in a particular
|
||||
store.</p><div class="table"><a name="d0e1406"></a><p class="title"><b>Table B.1. Query keywords</b></p><div class="table-contents"><table summary="Query keywords" border="1"><colgroup><col><col></colgroup><thead><tr><th>Logical keyword</th><th>Keyword expressions</th></tr></thead><tbody><tr><td><code class="code">AFTER</code></td><td><code class="literal">After</code>,
|
||||
<code class="literal">IsAfter</code></td></tr><tr><td><code class="code">BEFORE</code></td><td><code class="literal">Before</code>,
|
||||
<code class="literal">IsBefore</code></td></tr><tr><td><code class="code">CONTAINING</code></td><td><code class="literal">Containing</code>,
|
||||
<code class="literal">IsContaining</code>,
|
||||
<code class="literal">Contains</code></td></tr><tr><td><code class="code">BETWEEN</code></td><td><code class="literal">Between</code>,
|
||||
<code class="literal">IsBetween</code></td></tr><tr><td><code class="code">ENDING_WITH</code></td><td><code class="literal">EndingWith</code>,
|
||||
<code class="literal">IsEndingWith</code>,
|
||||
<code class="literal">EndsWith</code></td></tr><tr><td><code class="code">EXISTS</code></td><td><code class="literal">Exists</code></td></tr><tr><td><code class="code">FALSE</code></td><td><code class="literal">False</code>,
|
||||
<code class="literal">IsFalse</code></td></tr><tr><td><code class="code">GREATER_THAN</code></td><td><code class="literal">GreaterThan</code>,
|
||||
<code class="literal">IsGreaterThan</code></td></tr><tr><td><code class="code">GREATER_THAN_EQUALS</code></td><td><code class="literal">GreaterThanEqual</code>,
|
||||
<code class="literal">IsGreaterThanEqual</code></td></tr><tr><td><code class="code">IN</code></td><td><code class="literal">In</code>, <code class="literal">IsIn</code></td></tr><tr><td><code class="code">IS</code></td><td><code class="literal">Is</code>, <code class="literal">Equals</code>, (or no
|
||||
keyword)</td></tr><tr><td><code class="code">IS_NOT_NULL</code></td><td><code class="literal">NotNull</code>,
|
||||
<code class="literal">IsNotNull</code></td></tr><tr><td><code class="code">IS_NULL</code></td><td><code class="literal">Null</code>, <code class="literal">IsNull</code></td></tr><tr><td><code class="code">LESS_THAN</code></td><td><code class="literal">LessThan</code>,
|
||||
<code class="literal">IsLessThan</code></td></tr><tr><td><code class="code">LESS_THAN_EQUAL</code></td><td><code class="literal">LessThanEqual</code>,
|
||||
<code class="literal">IsLessThanEqual</code></td></tr><tr><td><code class="code">LIKE</code></td><td><code class="literal">Like</code>, <code class="literal">IsLike</code></td></tr><tr><td><code class="code">NEAR</code></td><td><code class="literal">Near</code>, <code class="literal">IsNear</code></td></tr><tr><td><code class="code">NOT</code></td><td><code class="literal">Not</code>, <code class="literal">IsNot</code></td></tr><tr><td><code class="code">NOT_IN</code></td><td><code class="literal">NotIn</code>,
|
||||
<code class="literal">IsNotIn</code></td></tr><tr><td><code class="code">NOT_LIKE</code></td><td><code class="literal">NotLike</code>,
|
||||
<code class="literal">IsNotLike</code></td></tr><tr><td><code class="code">REGEX</code></td><td><code class="literal">Regex</code>, <code class="literal">MatchesRegex</code>,
|
||||
<code class="literal">Matches</code></td></tr><tr><td><code class="code">STARTING_WITH</code></td><td><code class="literal">StartingWith</code>,
|
||||
<code class="literal">IsStartingWith</code>,
|
||||
<code class="literal">StartsWith</code></td></tr><tr><td><code class="code">TRUE</code></td><td><code class="literal">True</code>, <code class="literal">IsTrue</code></td></tr><tr><td><code class="code">WITHIN</code></td><td><code class="literal">Within</code>,
|
||||
<code class="literal">IsWithin</code></td></tr></tbody></table></div></div><br class="table-break"></div></div></div></div></body></html>
|