Instruction INSERT dans JPA

1. Vue d'ensemble

Dans ce rapide didacticiel, nous allons apprendre à exécuter une instruction INSERT sur des objets JPA .

Pour plus d'informations sur Hibernate en général, consultez notre guide complet sur JPA avec Spring et une introduction à Spring Data avec JPA pour une plongée approfondie dans ce sujet.

2. Objets persistants dans JPA

Dans JPA, chaque entité passant d'un état transitoire à un état géré est automatiquement gérée par EntityManager .

Les EntityManager vérifie si une entité existe déjà et décide alors si elle doit être inséré ou mis à jour. En raison de cette gestion automatique, t - il que des déclarations autorisées par l' APP SELECT, UPDATE et DELETE.

Dans les exemples ci-dessous, nous examinerons différentes manières de gérer et de contourner cette limitation.

3. Définition d'un modèle commun

Maintenant, commençons par définir une entité simple que nous utiliserons tout au long de ce tutoriel:

@Entity public class Person { @Id private Long id; private String firstName; private String lastName; // standard getters and setters, default and all-args constructors }

Définissons également une classe de référentiel que nous utiliserons pour nos implémentations:

@Repository public class PersonInsertRepository { @PersistenceContext private EntityManager entityManager; }

De plus, nous appliquerons l' annotation @Transactional pour gérer automatiquement les transactions par Spring. De cette façon, nous n'aurons pas à nous soucier de la création de transactions avec notre EntityManager, de la validation de nos modifications ou de la restauration manuelle en cas d'exception.

4. createNativeQuery

Pour les requêtes créées manuellement, nous pouvons utiliser la méthode EntityManager # createNativeQuery . Cela nous permet de créer n'importe quel type de requête SQL, pas seulement celles prises en charge par JPA. Ajoutons une nouvelle méthode à notre classe de référentiel:

@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(); }

Avec cette approche, nous devons définir une requête littérale comprenant les noms des colonnes et définir leurs valeurs correspondantes.

Nous pouvons maintenant tester notre référentiel:

@Test public void givenPersonEntity_whenInsertedTwiceWithNativeQuery_thenPersistenceExceptionExceptionIsThrown() { Person person = new Person(1L, "firstname", "lastname"); assertThatExceptionOfType(PersistenceException.class).isThrownBy(() -> { personInsertRepository.insertWithQuery(PERSON); personInsertRepository.insertWithQuery(PERSON); }); }

Dans notre test, chaque opération tente d'insérer une nouvelle entrée dans notre base de données. Puisque nous avons essayé d'insérer deux entités avec le même identifiant , la deuxième opération d'insertion échoue en lançant une PersistenceException .

Le principe ici est le même si nous utilisons @Query de Spring Data .

5. persister

Dans notre exemple précédent, nous avons créé des requêtes d'insertion, mais nous avons dû créer des requêtes littérales pour chaque entité. Cette approche n'est pas très efficace et entraîne beaucoup de code standard.

Au lieu de cela, nous pouvons utiliser la méthode persist d' EntityManager .

Comme dans notre exemple précédent, étendons notre classe de référentiel avec une méthode personnalisée:

@Transactional public void insertWithEntityManager(Person person) { this.entityManager.persist(person); }

Maintenant, nous pouvons tester à nouveau notre approche :

@Test public void givenPersonEntity_whenInsertedTwiceWithEntityManager_thenEntityExistsExceptionIsThrown() { assertThatExceptionOfType(EntityExistsException.class).isThrownBy(() -> { personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname")); personInsertRepository.insertWithEntityManager(new Person(1L, "firstname", "lastname")); }); }

Contrairement à l'utilisation de requêtes natives, nous n'avons pas à spécifier les noms de colonne et les valeurs correspondantes . Au lieu de cela, EntityManager gère cela pour nous.

Dans le test ci-dessus, nous nous attendons également à ce que EntityExistsException soit levée au lieu de sa superclasse PersistenceException qui est plus spécialisée et levée par persist .

D'autre part, dans cet exemple, nous devons nous assurer que nous appelons notre méthode d'insertion à chaque fois avec une nouvelle instance de Person. Sinon, il sera déjà géré par EntityManager, ce qui entraînera une opération de mise à jour.

6. Conclusion

Dans cet article, nous avons illustré des façons d'effectuer des opérations d'insertion sur des objets JPA. Nous avons examiné des exemples d'utilisation d'une requête native, ainsi que l'utilisation d' EntityManager # persist pour créer des instructions INSERT personnalisées.

Comme toujours, le code complet utilisé dans cet article est disponible à l'adresse over sur GitHub.