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

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

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

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

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

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.

Mostra a entidade categoria pra mim, por favor

@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
}

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

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

2 curtidas

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
}

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.