1. Visão geral
Neste tutorial, vamos aprender como implementar um campo sequencial gerado automaticamente para o MongoDB no Spring Boot.
Quando estamos usando o MongoDB como banco de dados para um aplicativo Spring Boot, não podemos usar @GeneratedValue anotação em nossos modelos, pois não está disponível. Portanto, precisamos de um método para produzir o mesmo efeito que teremos se estivermos usando JPA e um banco de dados SQL.
A solução geral para este problema é simples. Criaremos uma coleção (tabela) que armazenará a sequência gerada para outras coleções. Durante a criação de um novo registro, nós o usaremos para buscar o próximo valor.
2. Dependências
Vamos adicionar os seguintes iniciadores de inicialização de mola ao nosso pom.xml :
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<versionId>2.2.2.RELEASE</versionId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<versionId>2.2.2.RELEASE</versionId>
</dependency>
</dependencies>
A versão mais recente das dependências é gerenciada por spring-boot-starter-parent .
3. Coleções
Conforme discutido na visão geral, criaremos uma coleção que armazenará a sequência incrementada automaticamente para outras coleções. Chamaremos essa coleção de database_sequences. Ele pode ser criado usando o mongo shell ou MongoDB Compass. Vamos criar uma classe de modelo correspondente:
@Document(collection = "database_sequences")
public class DatabaseSequence {
@Id
private String id;
private long seq;
//getters and setters omitted
}
Vamos então criar um usuários coleção e um objeto de modelo correspondente, que armazenará os detalhes das pessoas que estão usando nosso sistema:
@Document(collection = "users")
public class User {
@Transient
public static final String SEQUENCE_NAME = "users_sequence";
@Id
private long id;
private String email;
//getters and setters omitted
}
No Usuário modelo criado acima, adicionamos um campo estático SEQUENCE_NAME, que é uma referência exclusiva à sequência incrementada automaticamente para os usuários coleção.
Também anotamos com o @Transient para evitar que ele seja persistido junto com outras propriedades do modelo.
4. Criando um novo registro
Até agora, criamos as coleções e modelos necessários. Agora, criaremos um serviço que gerará o valor incrementado automaticamente que pode ser usado como id para nossas entidades.
Vamos criar um SequenceGeneratorService que tem generateSequence() :
public long generateSequence(String seqName) {
DatabaseSequence counter = mongoOperations.findAndModify(query(where("_id").is(seqName)),
new Update().inc("seq",1), options().returnNew(true).upsert(true),
DatabaseSequence.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
Agora, podemos usar o comando generateSequence() ao criar um novo registro:
User user = new User();
user.setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME));
user.setEmail("[email protected]");
userRepository.save(user);
Para listar todos os usuários, usaremos o UserRepository :
List<User> storedUsers = userRepository.findAll();
storedUsers.forEach(System.out::println);
Como está agora, temos que definir o campo id toda vez que criamos uma nova instância do nosso modelo. Podemos contornar esse processo criando um ouvinte para eventos de ciclo de vida do Spring Data MongoDB.
Para fazer isso, criaremos um UserModelListener que estende AbstractMongoEventListener
@Override
public void onBeforeConvert(BeforeConvertEvent<User> event) {
if (event.getSource().getId() < 1) {
event.getSource().setId(sequenceGenerator.generateSequence(User.SEQUENCE_NAME));
}
}
Agora, sempre que salvamos um novo Usuário, o código será definido automaticamente.