DATAJPA-54 - Added forCounting() flag to @QueryHints.

The flag defaults to true and allows disabling of QueryHints being applied to the count query additionally triggered for pagination.
This commit is contained in:
Oliver Gierke
2011-09-06 13:47:38 +02:00
parent 6fec65b504
commit a5cb8ee6c0
5 changed files with 95 additions and 3 deletions

View File

@@ -18,8 +18,8 @@
<para>The JPA module of Spring Data contains a custom namespace that
allows defining repository beans. It also contains certain features and
element attributes that are special to JPA. Generally the JPA
repositories can be set up using the <code>repositories</code> element:
</para>
repositories can be set up using the <code>repositories</code>
element:</para>
<example>
<title>Setting up JPA repositories using the namespace</title>
@@ -444,6 +444,33 @@ int setFixedFirstnameFor(String firstname, String lastname);</programlisting>
<code>clearAutomatically</code> attribute to
<literal>false</literal>;</para>
</section>
<section id="jpa.query-hints">
<title>Applying query hints</title>
<para>To apply JPA <interfacename>QueryHint</interfacename>s to the
queries declared in your repository interface you can use the
<interfacename>QueryHints</interfacename> annotation. It takes an array
of JPA <interfacename>QueryHint</interfacename> annotations plus a
boolean flag to potentially disable the hints applied to the addtional
count query triggered when applying pagination.</para>
<example>
<title>Using QueryHints with a repository method</title>
<programlisting language="java">public interface UserRepository extends Repository&lt;User, Long&gt; {
@QueryHints(value = { @QueryHint(name = "name", value = "value")},
forCounting = false)
Page&lt;User&gt; findByLastname(String lastname, Pageable pageable);
}</programlisting>
<para>The just shown declaration would apply the configured
<interfacename>QueryHint</interfacename> for that actually query but
omit applying it to the count query triggered to calculate the total
number of pages.</para>
</example>
</section>
</section>
<section id="specifications">

View File

@@ -34,5 +34,18 @@ import javax.persistence.QueryHint;
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryHints {
/**
* The {@link QueryHint}s to apply when the query will be executed.
*
* @return
*/
QueryHint[] value() default {};
/**
* Defines whether the configured {@link QueryHint}s shall be applied for count queries during pagination as well.
* Defaults to {@literal true}.
*
* @return
*/
boolean forCounting() default true;
}

View File

@@ -131,7 +131,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
}
protected TypedQuery<Long> createCountQuery(Object[] values) {
return applyHints(doCreateCountQuery(values), method);
TypedQuery<Long> countQuery = doCreateCountQuery(values);
return method.applyHintsToCountQuery() ? applyHints(countQuery, method) : countQuery;
}
/**

View File

@@ -93,6 +93,18 @@ public class JpaQueryMethod extends QueryMethod {
return result;
}
/**
* Returns whether the potentially configured {@link QueryHint}s shall be applied when triggering the count query for
* pagination.
*
* @return
*/
boolean applyHintsToCountQuery() {
QueryHints hints = getAnnotation(method, QueryHints.class);
return hints != null ? hints.forCounting() : false;
}
/**
* Returns the {@link QueryExtractor}.
*

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2008-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.query;
import static org.mockito.Mockito.*;
@@ -65,10 +80,34 @@ public class AbstractJpaQueryTests {
verify(result).setHint("foo", "bar");
}
/**
* @see DATAJPA-54
* @throws Exception
*/
@Test
public void skipsHintsForCountQueryIfConfigured() throws Exception {
Method method = SampleRepository.class.getMethod("findByFirstname", String.class);
QueryExtractor provider = PersistenceProvider.fromEntityManager(em);
JpaQueryMethod queryMethod = new JpaQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
provider);
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[] { "Dave" });
verify(result).setHint("bar", "foo");
result = jpaQuery.createCountQuery(new Object[] { "Dave" });
verify(result, never()).setHint("bar", "foo");
}
interface SampleRepository extends Repository<User, Integer> {
@QueryHints({ @QueryHint(name = "foo", value = "bar") })
List<User> findByLastname(String lastname);
@QueryHints(value = { @QueryHint(name = "bar", value = "foo") }, forCounting = false)
List<User> findByFirstname(String firstname);
}
class DummyJpaQuery extends AbstractJpaQuery {