Spring Data: "Supprimer par" est-il pris en charge?

100

J'utilise Spring JPA pour accéder à la base de données. Je suis capable de trouver des exemples tels que findByName et countByName, pour lesquels je n'ai pas à écrire d'implémentation de méthode. J'espère trouver des exemples pour supprimer un groupe d'enregistrements en fonction de certaines conditions.

Spring JPA prend-il en charge la suppression de type deleteByName? Tout pointeur est apprécié.

Cordialement et merci.

curieux1
la source

Réponses:

185

Réponse obsolète (Spring Data JPA <= 1.6.x) :

@Modifyingannotation à la rescousse. Vous devrez cependant fournir votre comportement SQL personnalisé.

public interface UserRepository extends JpaRepository<User, Long> {
    @Modifying
    @Query("delete from User u where u.firstName = ?1")
    void deleteUsersByFirstName(String firstName);
}

Mettre à jour:

Dans les versions modernes de printemps de données JPA (> = 1.7.x) requête dérivation pour delete, removeet les countopérations est accessible.

public interface UserRepository extends CrudRepository<User, Long> {

    Long countByFirstName(String firstName);

    Long deleteByFirstName(String firstName);

    List<User> removeByFirstName(String firstName);

}
Andrey Atapin
la source
2
@AndreyAtapin Downvote car ce n'est plus une bonne réponse. Peut-être le supprimer? L'une des failles de stackoverflows est la gestion des changements de version / corrections de bogues associés aux bibliothèques en question.
Ben George
1
@webgeek, j'avais l'habitude de résoudre ce problème avec DELETE FROM x WHERE id = ?1 or parent_id = ?1. Btw, assurez-vous que vous n'avez pas de type parent__id(avez-vous un double tiret bas par intention?). Pourquoi utilisez-vous une option de requête native?
Andrey Atapin
4
Même si j'utilise 1.7.4, l'annotation @Transactional est nécessaire au-dessus de la méthode de requête pour que la suppression soit réussie
gokhansari
40
En règle générale, dans une application, vous aurez des classes / méthodes @ Service et celles-ci appelleront les référentiels. Et les méthodes publiques @ Service doivent être les méthodes marquées @ Transactionnel car les transactions sont basées sur des cas d'utilisation. Cela signifie qu'un cas d'utilisation doit être entièrement validé ou annulé. Pas chaque méthode de référentiel individuelle. Veuillez donc NE PAS utiliser @ Transactional sur les méthodes de référentiel. Mais sur les méthodes de service qui utilisent le référentiel.
user1567291
1
Faire @Transactional au repo signifie un service interne si vous appelez le repo plusieurs fois, chacun aura une transaction diff, donc annulez dans une requête. Si vous fournissez au niveau du service, toute votre fonction sera annulée en cas d'erreur.
P Satish Patro
78

La dérivation de requêtes de suppression à l'aide d'un nom de méthode donné est prise en charge à partir de la version 1.6.0.RC1 de Spring Data JPA. Les mots remove- clés et deletesont pris en charge. Comme valeur de retour, on peut choisir entre le nombre ou une liste d'entités supprimées.

Long removeByLastname(String lastname);

List<User> deleteByLastname(String lastname);
Christoph Strobl
la source
7

Si vous regardez le code source de Spring Data JPA, et en particulier la PartTreeJpaQueryclasse, vous verrez qu'il tente d'instancier PartTree. À l'intérieur de cette classe, l'expression régulière suivante

private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get|count|query)(\\p{Lu}.*?)??By")

devrait indiquer ce qui est autorisé et ce qui ne l'est pas.

Bien sûr, si vous essayez d'ajouter une telle méthode, vous verrez en fait que cela ne fonctionne pas et vous obtenez le stacktrace complet.

Je dois noter que j'utilisais la version 1.5.0.RELEASEde Spring Data JPA

geoand
la source
6

2 façons: -

1ère requête personnalisée

@Modifying
@Query("delete from User where firstName = :firstName")
void deleteUsersByFirstName(@Param("firstName") String firstName);

2ème une requête JPA par méthode

List<User> deleteByLastname(String lastname);

Lorsque vous utilisez la requête par méthode (2ème manière), il effectuera d'abord un appel get

select * from user where last_name = :firstName

Ensuite, il le chargera dans une liste puis il appellera delete id un par un

delete from user where id = 18
delete from user where id = 19

Récupérez d'abord la liste des objets, puis la boucle for pour supprimer l'id un par un

Mais, la 1ère option (requête personnalisée),

C'est juste une seule requête. Elle supprimera partout où la valeur existe.

Passez également par ce lien https://www.baeldung.com/spring-data-jpa-deleteby

P Satish Patro
la source
1
Merci pour l'info!
curieux1
2

Si vous utilisez des méthodes de suppression prédéfinies fournies directement par Spring JPA, deux requêtes ci-dessous seront exécutées par le framework.

  • Commencez par collecter des données (comme l'id et une autre colonne) en utilisant la requête de sélection d'exécution avec la clause where de la requête de suppression.

  • puis après avoir obtenu le résultat de la première requête, les secondes requêtes de suppression seront exécutées pour tous les id (une par une)

    Remarque: ce n'est pas une manière optimisée pour votre application car de nombreuses requêtes seront exécutées pour une seule requête de suppression MYSQL.

Il s'agit d'une autre méthode optimisée pour supprimer le code de requête, car une seule requête de suppression s'exécutera à l'aide des méthodes personnalisées ci-dessous.



@NamedNativeQueries({

@NamedNativeQuery(name = "Abc.deleteByCreatedTimeBetween",
            query = "DELETE FROM abc WHERE create_time BETWEEN ?1 AND ?2")
    ,

    @NamedNativeQuery(name = "Abc.getByMaxId",
            query = "SELECT max(id) from abc")
})

@Entity
public class Abc implements Serializable {

}

@Repository
public interface AbcRepository extends CrudRepository {

    int getByMaxId();

    @Transactional
    @Modifying
    void deleteByCreatedTimeBetween(String startDate, String endDate);
}
Suneet Khurana
la source
1

Soyez prudent lorsque vous utilisez une requête dérivée pour la suppression par lots. Ce n'est pas ce que vous attendez: DeleteExecution

Andrey Ofim
la source
Salut. Si vous indiquez RBAR (ligne par ligne angoissante), pourriez-vous ajouter cela à votre réponse? (et je vais voter pour). Je devine un peu ce que vous faites remarquer ici.
grenadeCoder
0

Oui, la méthode deleteBy est prise en charge Pour l'utiliser, vous devez annoter la méthode avec @Transactional

amoljdv06
la source