Skip to content

Latest commit

 

History

History
273 lines (209 loc) · 9.22 KB

repositories.adoc

File metadata and controls

273 lines (209 loc) · 9.22 KB

GemFire Repositories

Introduction

Spring Data GemFire provides support to use the Spring Data Repository abstraction to easily persist entities into GemFire and execute queries. A general introduction to the Repository programming model has been provided here.

Spring Configuration

To bootstrap Spring Data Repositories you use the <repositories/> element from the GemFire Data namespace:

Example 1. Bootstrap GemFire Repositories
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/data/gemfire
                           http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd>

  <gfe-data:repositories base-package="com.acme.repository" />

</beans>

This configuration snippet will look for interfaces below the configured base package and create Repository instances for those interfaces backed by a SimpleGemFireRepository. Note that you have to have your domain classes correctly mapped to configured Regions or the bootstrap process will fail otherwise.

Executing OQL Queries

The GemFire Repositories allow the definition of query methods to easily execute OQL Queries against the Region the managed entity is mapped to.

Example 2. Sample Repository
@Region("myRegion")
public class Person { … }
public interface PersonRepository extends CrudRepository<Person, Long> {

  Person findByEmailAddress(String emailAddress);

  Collection<Person> findByFirstname(String firstname);

  @Query("SELECT * FROM /Person p WHERE p.firstname = $1")
  Collection<Person> findByFirstnameAnnotated(String firstname);

  @Query("SELECT * FROM /Person p WHERE p.firstname IN SET $1")
  Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
}

The first method listed here will cause the following query to be derived: SELECT x FROM /MyRegion x WHERE x.emailAddress = $1. The second method works the same way except it’s returning all entities found whereas the first one expects a single result value. In case the supported keywords are not sufficient to declare your query or the method name gets to verbose you can annotate the query methods with @Query as seen for methods 3 and 4.

Table 1. Supported keywords for query methods
Keyword Sample Logical result

GreaterThan

findByAgeGreaterThan(int age)

x.age > $1

GreaterThanEqual

findByAgeGreaterThanEqual(int age)

x.age >= $1

LessThan

findByAgeLessThan(int age)

x.age < $1

LessThanEqual

findByAgeLessThanEqual(int age)

x.age ⇐ $1

IsNotNull, NotNull

findByFirstnameNotNull()

x.firstname =! NULL

IsNull, Null

findByFirstnameNull()

x.firstname = NULL

In

findByFirstnameIn(Collection<String> x)

x.firstname IN SET $1

NotIn

findByFirstnameNotIn(Collection<String> x)

x.firstname NOT IN SET $1

IgnoreCase

findByFirstnameIgnoreCase(String firstName)

x.firstname.equalsIgnoreCase($1)

(No keyword)

findByFirstname(String name)

x.firstname = $1

Like

findByFirstnameLike(String name)

x.firstname LIKE $1

Not

findByFirstnameNot(String name)

x.firstname != $1

IsTrue, True

findByActiveIsTrue()

x.active = true

IsFalse, False

findByActiveIsFalse()

x.active = false

OQL Query Extensions with Annotations

Many query languages, such as Pivotal GemFire’s OQL (Object Query Language), have extensions that are not directly supported by the Spring Data Commons Repository infrastructure.

One of Spring Data Commons' Repository infrastructure goals is to function as the lowest common denominator to maintain support and portability across the widest array of data stores available and in use for application development today. Technically, this means developers can access multiple different data stores supported by Spring Data Commons within their applications by reusing their existing application-specific Repository interfaces, a very convenient and powerful abstraction.

To support GemFire’s OQL Query language extensions and maintain portability across data stores, Spring Data GemFire adds support for OQL Query extensions by way of Java Annotations. These new Annotations will be ignored by other Spring Data Repository implementations (e.g. Spring Data Redis) that don’t have similar query language extensions.

For instance, many data stores will most likely not implement GemFire’s OQL IMPORT keyword. By implementing IMPORT as an Annotation (@Import) rather than as part of the query method signature (specifically, the method 'name'), this will not interfere with the parsing infrastructure when evaluating the query method name to construct the appropriate data store language appropriate query.

Currently, the set of OQL Query language extensions that are supported by Spring Data GemFire include:

Table 2. Supported OQL Query extensions for query methods
Keyword Annotation Description Arguments

HINT

@Hint

OQL Query Index Hints

String[] (e.g. @Hint({ "IdIdx", "TxDateIdx" }))

IMPORT

@Import

Qualify application-specific types.

String (e.g. @Import("org.example.app.domain.Type"))

LIMIT

@Limit

Limit the returned query result set.

Integer (e.g. @Limit(10); default is Integer.MAX_VALUE)

TRACE

@Trace

Enable OQL Query specific debugging.

NA

As an example, suppose you have a Customers application domain type and corresponding GemFire Region along with a CustomerRepository and a query method to lookup Customers by last name, like so…​

Example 3. Sample Repository
package ...;

import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.Region;
...

@Region("Customers")
public class Customer ... {

  @Id
  private Long id;

  ...
}
package ...;

import org.springframework.data.gemfire.repository.GemfireRepository;
...

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("LastNameIdx")
  @Import("org.example.app.domain.Customer")
  List<Customer> findByLastName(String lastName);

  ...
}

This will result in the following OQL Query:

<TRACE> <HINT 'LastNameIdx'> IMPORT org.example.app.domain.Customer; SELECT * FROM /Customers c WHERE c.lastName = $1 LIMIT 10

Spring Data GemFire’s Repository extension support is careful not to create conflicting declaratives when the Query Annotation extensions are used in combination with the @Query annotation.

For instance, suppose you have a raw @Query annotated query method defined in your CustomerRepository like so…​

Example 4. CustomerRepository
public interface CustomerRepository extends GemfireRepository<Customer, Long> {

  @Trace
  @Limit(10)
  @Hint("CustomerIdx")
  @Import("org.example.app.domain.Customer")
  @Query("<TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5")
  List<Customer> findDistinctCustomersByReputationGreaterThanOrderByReputationDesc(Integer reputation);
}

This query method results in the following OQL Query:

IMPORT org.example.app.domain.Customer; <TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5

As you can see, the @Limit(10) annotation will not override the LIMIT defined explicitly in the raw query. As well, @Hint("CustomerIdx") annotation does not override the HINT explicitly defined in the raw query. Finally, the @Trace annotation is redundant and has no additional effect.

Note

The "ReputationIdx" Index is probably not the most sensible index given the number of Customers who will possibly have the same value for their reputation, which will effectively reduce the effectiveness of the index. Please choose indexes and other optimizations wisely as an improper or poorly choosen index and have the opposite effect on your performance given the overhead in maintaining the index. The "ReputationIdx" was only used to serve the purpose of the example.