Spring-Data Jpa + hibernate. Problema com delete()

10 respostas
javamysqlspring
thimor

Estou utilizando Spring-Data JPA com Hibernate e estou com problema no método delete() da interface JpaRepository.

Quando eu chamo o método delete passando o objeto, determinados objetos ele exclui, outros objetos ele não exclui. Passa pelo método, não da exceção, e simplesmente nao exclui. Quando eu uso o delete passando o ID funciona. Alguém sabe explicar por que isso acontece?

Não funciona:

/*
*  Assim NAO funciona
*/
@override
public void excluir(Categoria categoria) {
        categoriaRepository.delete(categoria);
}

Funciona:

/*
*  Assim funciona
*/
@override
public void excluir(Categoria categoria) {
        categoriaRepository.delete(categoria.getId());
}

public interface CategoriaRepository extends JpaRepository<Categoria, Integer> {
}

@NoRepositoryBean
public interface JpaRepository<T extends Object, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {

     public List<T> findAll();

     public List<T> findAll(Sort sort);

     public List<T> findAll(Iterable<ID> itrbl);

     public <S extends T> List<S> save(Iterable<S> itrbl);

     public void flush();

     public <S extends T> S saveAndFlush(S s);

      public void deleteInBatch(Iterable<T> itrbl);

      public void deleteAllInBatch();

      public T getOne(ID id);
}

@NoRepositoryBean
public interface CrudRepository<T extends Object, ID extends Serializable> extends Repository<T, ID> {

    public <S extends T> S save(S s);

    public <S extends T> Iterable<S> save(Iterable<S> itrbl);

    public T findOne(ID id);

    public boolean exists(ID id);

    public Iterable<T> findAll();

    public Iterable<T> findAll(Iterable<ID> itrbl);

    public long count();

    public void delete(ID id);

    public void delete(T t);

    public void delete(Iterable<? extends T> itrbl);

    public void deleteAll();
}

10 Respostas

Dragoon

Coloque a implementação dessa interface na sua pergunta?

thimor

as interfaces sao do spring-jpa nao sei as classes que as implementam. vou procurar no manual

jacoboliveira

Ola thimor, vou tentar explicar e depois mostrar a solução, certo? Vamos lá, do jeito que VC esta fazendo provavelmente VC não esta recuperando do banco o objeto categoria, pois se uma hora ele insere e outra hora ele não insere isso é devido a um conceito do hibernate que a gente chama de entidade gerenciada pelo hibernate, quando vc faz um findbyid VC esta recuperando uma entidade com uma informação a mais e quem faz isso é chamado Proxy, este faz o trabalho de conter esta informação a mais chamada de managed /gerenciado
Agora se ele esta managed então ele esta pronto para persistente state/estado de persistência
Solução

categoriaRepository.delete(categoriaRepository.findOne(categoria.getId));

Dai VC pode dizer mais antes eu deletar por id, mas ai tem outros situações, por exemplo chave compostas ou até mesmo padrão de codificação de sempre passar um objeto pra fazer as operações de persistência e etc

thimor

ola bom dia. Foi a primeira coisa que tentei. fazer um find e mandar deletar. Porem nao deu certo. Eu acredito que seja por causa do relacionamento esse problema. Cada categoria recebe um id da tabela setor.

Entao em todos os relacionamentos 1-N a tabela que recebe o ID eu nao consigo excluir por esse metodo delete. Eu acho estranho pq como eh uma tabela “filha” ela nao deveria ter restrição de delete.

jacoboliveira

Mostra a entidade categoria pra mim, por favor

thimor
@Entity
public class Secao implements Serializable {

      private static final long serialVersionUID = 1L;
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Integer id;

      @Column(name = "nome", length = 30, nullable = false)
      private String nome;

      @OneToMany(cascade = CascadeType.ALL, mappedBy = "secao", fetch = FetchType.LAZY)
      private List<Categoria> categorias;

      @OneToMany(cascade = CascadeType.ALL, mappedBy = "secao", fetch = FetchType.LAZY)
      private List<Familia> familias;

      public Secao() {
      }
      //gets e sets
  }

   @Entity
   @Table(name = "categoria")
    public class Categoria implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "nome", length = 30, nullable = false)
    private String nome;

     @JoinColumn(name = "id_secao", referencedColumnName = "id", nullable = false)
     @ManyToOne(optional = false)
     private Secao secao;

     @OneToMany(cascade = CascadeType.ALL, mappedBy = "categoria", fetch = FetchType.LAZY)
     private List<Familia> familias;

     public Categoria() {
         secao = new Secao();
     }

    //gets e sets
}
jacoboliveira

Olha thimor até agora não vi nada de errado tem que ver se o objeto Categoria esta vindo com o id tenta “debugar”, outra coisa mostra a classe família para eu ver, e ter certeza que esta tudo mapeado certo

igor_ks

Tente sobreescrever os métodos equals e hashCode. Pode ser que o Sprint-data não esteja achando o objeto igualzinho ao passado, por causa da falta do equals e hashCode, mesmo que seja os mesmos valores

thimor

a classe Secao, apaga com o metodo delete(T t). as classes Categoria e Familia so apagam com o delete(ID id)

@Entity
@Table(name = "familia")
public class Familia implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "nome", length = 30, nullable = false)
     private String nome;

    @JoinColumn(name = "id_secao", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Secao secao;

    @JoinColumn(name = "id_categoria", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Categoria categoria;

    public Familia() {
       secao = new Secao();
       categoria = new Categoria();
    }
    //gets e sets
}
L

thimor,

Como o igor_ks disse, parece ser um problema de escolha dos métodos equals e hashCode. Na hora de realizar o delete, se os parâmetros não baterem exatamente, ele simplesmente não os identifica (e portanto não os deleta) sem retornar qualquer informação de falha para o usuário.

Outra coisa, se você estiver usando JPA 2.0, nos atributos @XXXtoMany você pode usar orphanRemoval=true.

Criado 27 de junho de 2016
Ultima resposta 29 de jun. de 2016
Respostas 10
Participantes 5