Solving a problem

In this day and age, why are we still writing queries like this:

    SELECT * 
    FROM PERSON 
    WHERE FIRST_NAME = %1

That type of query must be thirty years old! The ANSI spec for SQL was released in 1986, and its effects can be seen in countless languages.

So, is it any better to write something more like this:

    SELECT e 
    FROM Employee e 
    WHERE e.firstName = :name 

The last bit of code is JPA (Java Persistence API), based upon the open source Hibernate project (which has become JPA's reference implementation). Is this Java's improvement over writing pure SQL?

Maybe this fragment below is an enhancement?

    create 
      .select() 
      .from(EMPLOYEE) 
      .where(EMPLOYEE.FIRST_NAME.equal(name)) 
      .fetch() 

That last code snippet is jOOQ, and can help with code completion, but it seems that we are, basically, doing the same thing we've been doing for decades.

Especially, considering that we could do the same thing by merely creating this:

    interface EmployeeRepository 
     extends ReactiveCrudRepository<Employee, Long> { 
 
       Flux<Employee> findByFirstName(Mono<String> name); 
    } 

This preceding declarative interface does the exact same thing, but without writing a single query in any language.

By extending Spring Data's ReactiveCrudRepository, we are granted an out-of-the-box set of CRUD operations (save, findById, findAll, delete, deleteById, count, exists, and more). We also have the ability to add custom finders purely by method signature (findByFirstName in this example).

When Spring Data sees an interface extending its Repository marker interface (which ReactiveCrudRepository does), it creates a concrete implementation. It scans every method, and parses their method signatures. Seeing findBy, it knows to look at the rest of the method name, and start extracting property names based on the domain type (Employee). Because it can see that Employee has firstName, it has enough information to fashion a query. This also tips it off about expected criteria in the arguments (name). Finally, Spring Data looks at the return type to decide what result set to assemble--in this case, a Reactor Flux that we started to explore in the previous chapter. The entire query (not the query results), once assembled, is cached, so, there is no overhead in using the query multiple times.

In a nutshell, by following a very simple convention, there is no need to handwrite a query at all. And while this book is focused on MongoDB and its corresponding Mongo Query Language, this concept applies to SQL, JPA, Cassandra Query Language, or any other supported data store.

Spring Data does not engage in code generation of any code. Code generation has had a flaky history. Instead, it uses various tactics to pick a base class that handles the minimum set of operations while wrapping it with a proxy that implements the declared interface, bringing onboard the dynamic query handler.

This mechanism of managing data is revolutionary, making Spring Data one of the most popular Spring portfolio projects, second only to the Spring Framework itself and Spring Security (and of course Spring Boot).

Wait a second, didn't we just mention using MongoDB earlier?

Yup. That's why Spring Data's query-neutral approach is even better. Changing data stores doesn't require throwing away absolutely everything and starting over. The interface declared previously extends Spring Data Commons, not Spring Data MongoDB. The only data store details are in the domain object itself.

Instead of Employee being some JPA-based entity definition, we can work on a MongoDB document-based one instead, like this:

    @Data 
    @Document(collection="employees") 
    public class Employee { 
      @Id String id; 
      String firstName; 
      String lastName; 
    } 

This preceding MongoDB POJO can be described as follows:

  • The @Data Lombok annotation takes care of getters, setters, toString, equals, and hashCode functions.
  • @Document is an optional annotation that lets us spell out the MongoDB collection that this domain object will be stored under ("employees").
  • @Id is a Spring Data Commons annotation that flags which field is the key. (NOTE: When using Spring Data JPA, the required annotation is javax.persistence.Id, whereas, all other Spring-Data-supported stores utilize org.springframework.data.annotation.Id).
What is Spring Data Commons? It's the parent project for all Spring Data implementations. It defines several concepts implemented by every solution. For example, the concept of parsing finder signatures to put together a query request is defined here. But the bits where this is transformed into a native query is supplied by the data store solution itself. Spring Data Commons also provides various interfaces, allowing us to reduce coupling in our code to the data store, such as ReactiveCrudRepository, and others that we'll soon see.

Nothing else is needed to start writing Employee objects into the employees collection of our MongoDB database.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.14.93