Spring Data: “excluir por” é compatível?

99

Estou usando Spring JPA para acesso ao banco de dados. Consigo encontrar exemplos como findByName e countByName, para os quais não preciso escrever nenhuma implementação de método. Espero encontrar exemplos para excluir um grupo de registros com base em alguma condição.

O Spring JPA suporta exclusão semelhante a deleteByName? Qualquer ponteiro é apreciado.

Atenciosamente e obrigado.

curioso1
fonte

Respostas:

184

Resposta preterida (Spring Data JPA <= 1.6.x) :

@Modifyinganotação para o resgate. Porém, você precisará fornecer seu comportamento SQL personalizado.

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

Atualizar:

Em versões modernas de Primavera de dados JPA (> = 1.7.x) consulta de derivação para delete, removee countoperações está acessível.

public interface UserRepository extends CrudRepository<User, Long> {

    Long countByFirstName(String firstName);

    Long deleteByFirstName(String firstName);

    List<User> removeByFirstName(String firstName);

}
Andrey Atapin
fonte
2
@AndreyAtapin Downvote porque não é mais uma boa resposta. Talvez exclua? Uma das falhas do stackoverflows é lidar com as alterações de versão / correções de bugs associadas às bibliotecas em questão.
Ben George de
1
@webgeek, eu costumava resolver esse problema com DELETE FROM x WHERE id = ?1 or parent_id = ?1. Btw, certifique-se de que você não tem um tipo em parent__id(você tem um traço baixo duplo intencionalmente?). Por que você usa uma opção de consulta nativa?
Andrey Atapin
4
Mesmo que eu use 1.7.4, a anotação @Transactional é necessária acima do método de consulta para ter a exclusão bem-sucedida
gokhansari
40
Normalmente, em um aplicativo, você terá classes / métodos @ Service e esses estarão chamando os Repositórios. Os métodos públicos de @Serviço devem ser os métodos marcados com @ Transacional porque as transações são baseadas em casos de uso. O que significa que um caso de uso precisa ser totalmente confirmado ou retrocedido. Nem cada método de repositório individual. Portanto, POR FAVOR, NÃO use @ Transactional nos métodos de repositório. Mas nos métodos de serviço que usam o repositório.
user1567291
1
Tornar @Transactional no repo significa dentro do serviço, se você chamar o repo várias vezes, cada um terá uma transação diff, então rollback em 1 consulta. Se você fornecer no nível de serviço, toda a sua função será revertida em qualquer erro.
P Satish Patro
78

A derivação de consultas de exclusão usando o nome do método fornecido é suportada a partir da versão 1.6.0.RC1 do Spring Data JPA. As palavras remove- chave e deletesão suportadas. Como valor de retorno pode-se escolher entre o número ou uma lista de entidades removidas.

Long removeByLastname(String lastname);

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

Se você der uma olhada no código-fonte do Spring Data JPA, e particularmente na PartTreeJpaQueryclasse, verá que ele tenta instanciar PartTree. Dentro dessa classe, a seguinte expressão regular

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

deve indicar o que é permitido e o que não é.

Obviamente, se você tentar adicionar tal método, verá que ele não funciona e obterá o rastreamento de pilha completo.

Devo observar que estava usando a versão 1.5.0.RELEASEdo Spring Data JPA

geoand
fonte
6

2 maneiras: -

1ª consulta personalizada

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

2ª consulta JPA por método

List<User> deleteByLastname(String lastname);

Quando você vai com consulta por método (2ª via), ele primeiro fará uma chamada get

select * from user where last_name = :firstName

Então ele irá carregá-lo em uma lista Então irá chamar delete id um por um

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

Primeiro busque a lista de objetos e, em seguida, o loop para excluir o id um por um

Mas, a 1ª opção (consulta personalizada),

É apenas uma única consulta que excluirá onde quer que o valor exista.

Acesse também este link https://www.baeldung.com/spring-data-jpa-deleteby

P Satish Patro
fonte
1
Obrigado pela informação!
curioso 1
2

Se você usar métodos de exclusão predefinidos conforme fornecidos diretamente pelo spring JPA, as duas consultas abaixo serão executadas pela estrutura.

  • Primeiro, colete dados (como id e outra coluna) usando by execute select query com delete query where cláusula.

  • então, após obter o conjunto de resultados da primeira consulta, as consultas de exclusão da segunda serão executadas para todos os ids (um por um)

    Nota: Esta forma não é otimizada para seu aplicativo porque muitas consultas serão executadas para uma única consulta de exclusão MYSQL.

Esta é outra maneira otimizada de excluir o código de consulta porque apenas uma consulta de exclusão será executada usando os métodos personalizados abaixo.



@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
fonte
1

Tenha cuidado ao usar consulta derivada para exclusão de lote. Não é o que você espera: DeleteExecution

Andrey Ofim
fonte
Oi. Se você está apontando RBAR (linha por linha agonizante), você poderia adicionar isso à sua resposta? (e eu irei votar positivamente). Eu estou meio que adivinhando o que você está apontando aqui.
granadaCoder
0

Sim, o método deleteBy é compatível. Para usá-lo, você precisa anotar o método com @Transactional

amoljdv06
fonte