Instrução INSERT na JPA
1. Visão geral
Neste tutorial rápido, aprenderemos comoperform an INSERT statement on JPA objects.
Para obter mais informações sobre o Hibernate em geral, verifique nossos abrangentesguide to JPA with Springeintroduction to Spring Data with JPA para detalhes sobre este tópico.
2. Objetos persistentes no JPA
No JPA, cada entidade que vai de um estado transiente para gerenciado é tratada automaticamente peloEntityManager.
OEntityManager verifica se uma determinada entidade já existe e então decide se ela deve ser inserida ou atualizada. Por causa desse gerenciamento automático,the only statements allowed by JPA are SELECT, UPDATE andDELETE.
Nos exemplos abaixo, veremos diferentes maneiras de gerenciar e contornar essa limitação.
3. Definindo um modelo comum
Agora, vamos começar definindo uma entidade simples que usaremos ao longo deste tutorial:
@Entity
public class Person {
@Id
private Long id;
private String firstName;
private String lastName;
// standard getters and setters, default and all-args constructors
}
Além disso, vamos definir uma classe de repositório que usaremos para nossas implementações:
@Repository
public class PersonInsertRepository {
@PersistenceContext
private EntityManager entityManager;
}
Além disso, vamos aplicar a anotação@Transactional para lidar com as transações automaticamente até o Spring. Dessa forma, não teremos que nos preocupar em criar transações com nossoEntityManager, confirmando nossas alterações, ou executando rollback manualmente no caso de uma exceção.
4. createNativeQuery
Para consultas criadas manualmente, podemos usar o métodoEntityManager#createNativeQuery. Ele nos permite criar qualquer tipo de consulta SQL, não apenas as suportadas pelo JPA. Vamos adicionar um novo método à nossa classe de repositório:
@Transactional
public void insertWithQuery(Person person) {
entityManager.createNativeQuery("INSERT INTO person (id, first_name, last_name) VALUES (?,?,?)")
.setParameter(1, person.getId())
.setParameter(2, person.getFirstName())
.setParameter(3, person.getLastName())
.executeUpdate();
}
Com essa abordagem, precisamos definir uma consulta literal incluindo nomes das colunas e definir seus valores correspondentes.
Agora podemos testar nosso repositório:
@Test
public void givenPersonEntity_whenInsertedTwiceWithNativeQuery_thenPersistenceExceptionExceptionIsThrown() {
Person person = new Person(1L, "firstname", "lastname");
assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> {
personInsertRepository.insertWithQuery(PERSON);
personInsertRepository.insertWithQuery(PERSON);
});
}
Em nosso teste, toda operação tenta inserir uma nova entrada em nosso banco de dados. Como tentamos inserir duas entidades com o mesmoid, a segunda operação de inserção falhou ao lançar umPersistenceException.
O princípio aqui é o mesmo se estivermos usando@Query. do Spring Data
5. persist
No exemplo anterior, criamos consultas de inserção, mas tivemos que criar consultas literais para cada entidade. Essa abordagem não é muito eficiente e resulta em muito código padrão.
Em vez disso, podemos usar o métodopersist deEntityManager.
Como em nosso exemplo anterior, vamos estender nossa classe de repositório com um método personalizado:
@Transactional
public void insertWithEntityManager(Person person) {
this.entityManager.persist(person);
}
Agora, podemos testar nossa abordagem novamente:
@Test
public void givenPersonEntity_whenInsertedTwiceWithEntityManager_thenEntityExistsExceptionIsThrown() {
assertThatExceptionOfType(EntityExistsException.class).isThrownBy(() -> {
personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname"));
personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname"));
});
}
Em contraste com o uso de consultas nativas,we don’t have to specify column names and corresponding values. Em vez disso,EntityManager cuida disso para nós.
No teste acima, também esperamos queEntityExistsException seja lançado em vez de sua superclassePersistenceException que é mais especializado e lançado porpersist.
Por outro lado, neste exemplo, temos que nos certificar de quewe call our insert method each time with a new instance of Person. O contrário, já será gerenciado porEntityManager, resultando em uma operação de atualização.
6. Conclusão
Neste artigo, ilustramos maneiras de executar operações de inserção em objetos JPA. Vimos exemplos de como usar uma consulta nativa, bem como usarEntityManager#persist para criar instruções INSERT personalizadas.
Como sempre, o código completo usado neste artigo está disponívelover on GitHub.