Original title: Spring certified China Education Management Center - Spring Data Couchbase tutorial 8 (spring China Education Management Center)

4.8.3. Repository filler
If you use the Spring JDBC module, you may be familiar with DataSource's support for populating a with SQL scripts. There is a similar abstraction at the repository level, although it does not use SQL as the data definition language because it must be independent of the repository. Therefore, the filler supports XML (through Spring's OXM abstraction) and JSON (through Jackson) to define the data used to populate the repository.
Suppose you have a file named data JSON, which reads as follows:
Example 72 Data defined in JSON
[ { "_class" : "com.acme.Person", "firstname" : "Dave", "lastname" : "Matthews" }, { "_class" : "com.acme.Person", "firstname" : "Carter", "lastname" : "Beauford" } ]
You can populate the repository using the filler element of the repository namespace provided in Spring Data Commons. To populate the previous data into your person repository, declare a filler similar to the following:
Example 73 Declare a Jackson repository filler
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:repository="http://www.springframework.org/schema/data/repository" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/repository https://www.springframework.org/schema/data/repository/spring-repository.xsd"> <repository:jackson2-populator locations="classpath:data.json" /> </beans>
The previous declaration resulted in data The JSON file is read and deserialized by Jackson.
The type of JSON object ungrouping is checked_ The properties of the classJSON document. The infrastructure eventually selects the appropriate repository to handle the deserialized objects.
To use XML instead to define the data that the repository should populate, you can use the unmarshaller-populator element. You configure it to use one of the XML marshaller options available in Spring OXM. For more information, see the Spring reference documentation. The following example shows how to use JAXB to ungroup the repository filler:
Example 74 Declare the ungroup repository filler (using JAXB)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:repository="http://www.springframework.org/schema/data/repository" xmlns:oxm="http://www.springframework.org/schema/oxm" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/repository https://www.springframework.org/schema/data/repository/spring-repository.xsd http://www.springframework.org/schema/oxm https://www.springframework.org/schema/oxm/spring-oxm.xsd"> <repository:unmarshaller-populator locations="classpath:data.json" unmarshaller-ref="unmarshaller" /> <oxm:jaxb2-marshaller contextPath="com.acme" /> </beans>
5. Couchbase repository
The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement the data access layer for various persistent stores.
By default, if the operation is a single document operation and the ID is known, the operation is supported by Key/Value. For all other operations, N1QL queries are generated by default, so you must create an appropriate index for high-performance data access.
Note that you can adjust the required consistency for queries (see using consistent queries) and have different repositories supported by different buckets (see)[ couchbase.repository.multibucket])
5.1. to configure
Although there is always support for repositories, you need to enable them in general or for specific namespaces. If you extend AbstractCouchbaseConfiguration, simply use the @ EnableCouchbaseRepositories annotation. It provides many possible options to narrow or customize the search path. One of the most common options is base packages
Also note that if you are running in Spring Boot, autoconfiguration support has set comments for you, so you only need to use it if you want to override the defaults.
Example 75 Annotation based repository settings
@Configuration @EnableCouchbaseRepositories(basePackages = {"com.couchbase.example.repos"}) public class Config extends AbstractCouchbaseConfiguration { //... }
[ couchbase. repository. Advanced usage is described in [multibucket].
5.2. usage
In the simplest case, your repository will extend crudrepository < T, string >, where t is the entity you want to expose. Let's take a look at the repository of UserInfo:
Example 76 Userinfo repository
import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository<UserInfo, String> { }
Note that this is just an interface, not an actual class. In the background, when your context is initialized, the actual implementation of your repository description will be created and you can access them through regular bean s. This means that you will save a lot of boilerplate code while still exposing the full CRUD semantics to your service tier and applications.
Now, let's imagine that our @ Autowire UserRepository class makes use of it. What methods are available?

Great now! By defining only one interface, we can obtain the complete CRUD function on the managed entity.
Although public methods provide you with a wide variety of access patterns, you usually need to define custom access patterns. You can do this by adding method declarations to the interface, which will automatically resolve into requests in the background, as we will see in the next section.
5.3. Repositories and queries
5.3.1. Query based on N1QL
The prerequisite is to create a PRIMARY INDEX on the bucket where the entity is stored.
Here is an example:
Example 77 Extended UserInfo repository with N1QL queries
public interface UserRepository extends CrudRepository<UserInfo, String> { @Query("#{#n1ql.selectEntity} WHERE role = 'admin' AND #{#n1ql.filter}") List<UserInfo> findAllAdmins(); List<UserInfo> findByFirstname(String fname); }
Here, we see two query methods supported by N1QL.
The first method uses Query annotations to provide N1QL inline statements. Spiel (Spring expression language) is supported by the spiel expression block between #{and}. Spiel provides some N1QL specific values:
- #n1ql.selectEntity allows you to easily ensure that the statement will select all fields (including document ID and CAS value) required to build a complete entity.
- #n1ql.filter adds a condition in the WHERE clause to match the entity type with the field Spring Data uses to store type information.
- #n1ql.bucket will be replaced with the name of the bucket where the entity is stored and escaped in reverse quotation marks.
- #n1ql.fields is replaced with a list of fields needed to rebuild the entity (for example, for a SELECT clause).
- #n1ql.delete will be replaced by the delete from declaration.
- #n1ql.returning will be replaced by the return clause required to rebuild the entity.
We recommend that you always use selectentityspiel and WHERE clause filter with spiel (otherwise your query may be affected by entities from other repositories).
String based queries support parameterized queries. You can use position placeholders such as "$1", in which case each method parameter will be mapped to $1, $2, $3 in order Alternatively, you can use a named placeholder using the "$somestring" syntax. Method parameters will match their corresponding placeholders with parameter names, which can be overridden by annotating each parameter (aPageable or except Sort), for example. You can't mix these two methods in a query. If you do, you'll get@ Param@Param("someString")IllegalArgumentException
Note that you can mix N1QL placeholders and spiel. The N1QL placeholder will still consider all method parameters, so be sure to use the correct index, as shown in the following example:
Example 78 Inline query with mixed spiel and N1QL placeholders
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND #{[0]} = $2") public List<User> findUsersByDynamicCriteria(String criteriaField, Object criteriaValue)
This allows you to generate queries similar to, for example. AND name = "someName" or AND age = 3, using a single method declaration.
You can also perform a single projection in the N1QL query (provided that it selects only one field and returns only one result, usually an aggregate, such as COUNT, AVG, MAX...). Such a projection will have a simple return type, such as long,boolean, or String. This is not intended to predict the DTO.
Another example: #{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND test = $1 amount to SELECT #{#n1ql.fields} FROM #{#n1ql.bucket} WHERE #{#n1ql.filter} AND test = $1
Practical application of spiel and Spring Security
Spiel is useful when you want to query against data injected by other Spring components, such as Spring Security. This is what you need to do to extend the spiel context to access such external data.
First, you need to implement a Evaluationcontextension (using the following support classes):
class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport { @Override public String getExtensionId() { return "security"; } @Override public SecurityExpressionRoot getRootObject() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); return new SecurityExpressionRoot(authentication) {}; } }
Then, in order for Spring Data Couchbase to access the associated spiel value, all you need to do is declare a corresponding bean in the configuration:
@Bean EvaluationContextExtension securityExtension() { return new SecurityEvaluationContextExtension(); }
This is useful for making queries based on the role of connected users, for example:
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND " + "role = '?#{hasRole('ROLE_ADMIN') ? 'public_admin' : 'admin'}'") List<UserInfo> findAllAdmins(); //only ROLE_ADMIN users will see hidden admins
Delete query example:
@Query("#{#n1ql.delete} WHERE #{#n1ql.filter} AND " + "username = $1 #{#n1ql.returning}") UserInfo removeUser(String username);
The second method uses spring data's query derivation mechanism to build N1QL queries FROM method names and parameters. This will result in a query as follows: SELECT... FROM... Where firstname = "valueofnameatruntime" You can combine these conditions and even count countByFirstname with a similar name or restrict findFirst3ByLastname with a similar name
In fact, the generated N1QL query will also include an additional N1QL standard to select only documents that match the entity class of the repository.
Most spring data keywords are supported:@ Keywords supported in Query (N1QL) method names


You can use this method to use both count query and limit query results.
With N1QL, another possible interface to the repository is Pagingandsorting repository (extend CrudRepository). It adds two methods:
