CascadeType.ALL does not work. Am I using it wrong?

7

In my code, I have the Author and Book classes with the Many To One relationship, as below:

Author.java

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Type;
@Entity
public class Autor implements Serializable{
    @OneToMany(mappedBy = "autor", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<Livro> livros;

    // outras coisas...
}

Book.java

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
@Entity
public class Livro implements Serializable{
    @ManyToOne
    private Autor autor;

    // outras coisas...
}

Note: I'm using MYSQL and Hibernate 3.
I can do the basic operations with this code: create, read, update and remove. But I can only delete a Autor that has no Livro related to it. When I try to delete a Autor that has Livros , I get this error:

  

Can not delete or update a parent row: a foreign key constraint fails ( livros . livro , CONSTRAINT FK4607E763FA6B4EF FOREIGN KEY ( autor_id ) REFERENCES autor

I would like that when I erase an Author that already has related Books, these would also be removed from the database. I thought the goal of id was this, but I was not successful using it. Where am I going wrong?
Thank you.

EDIT 1

Looking for more on the internet about this problem, I came across this site . There it is said that you can not mix JPA annotations with Hibernate (just what I was doing). Replaced CascadeType.ALL with @OneToMany([...], cascade = CascadeType.ALL) , but to no avail. Below the modified class and delete method of my class @Cascade(CascadeType.ALL) .

Author.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Type;
@Entity
public class Autor implements Serializable{
    @OneToMany(mappedBy = "autor", fetch = FetchType.EAGER)
    @Cascade({CascadeType.ALL})
    private List<Livro> livros;

    // outras coisas...
}

Dao.java

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class Dao <Classe>{
    public void delete(Classe c){
        session = HibernateUtil.getSessionFactory().openSession();
        transaction = session.beginTransaction();
        session.delete(c);
        transaction.commit();
        session.close();
    }
    // Outras coisas...
}

EDIT 2

In response, Mark said that you should not mix JPA with Hibernate, but that's how I was doing it from the beginning (and it did not work). I looked for examples on the internet, and my class is basically the same as all the others; the only difference is that I can not make it work. Is it possible that this is a Hibernate version problem? Use o 3.5.6.

EDIT 3

As Marcos Sousa asked, here is my complete project on Github: link

    
asked by anonymous 20.12.2016 / 14:03

1 answer

6

In fact, you should not mix Hibernate annotations in JPA with the JPA note. the JPA is the specification and Hibernate implements it in case of implementation changes for EclipseLink for example, there would be no problems since both implement JPA , that is, JPA is the default.

1st Keep in mind the use and standardization of JPA in your code.

2nd About the relationship of your entities: in cases where a Book is written by several authors? Would not it be a ManyToMany relationship?

3rd Try updating the Hibernate library, you will not have many problems (edit note 2: I'm using hibernate in version 5.2.3.Final) .

4th is a two-way auxiliary (edit note 3) relationship with bidirectional OneToMany relationship.

BOOK

package br.com.livraria.model;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;


@Entity
public class Livro implements Serializable {
    private static final long serialVersionUID = 1L;

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

    private String titulo; 

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="autor_id")
    private Autor autor;


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitulo() {
        return titulo;
    }
    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    public Autor getAutor() {
        return autor;
    }
    public void setAutor(Autor autor) {
        this.autor = autor;
    }


}

AUTHOR

package br.com.livraria.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Autor implements Serializable {
    private static final long serialVersionUID = 1L;

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

    private String nome;

    @OneToMany(mappedBy="autor", cascade=CascadeType.ALL)
    private List<Livro> livros = new ArrayList<>();

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public List<Livro> getLivros() {
        return livros;
    }

    public void setLivros(List<Livro> livros) {
        this.livros = livros;
    }

}

5th I refuted the design of your code, but in my configuration environment: I'm using a WildFly application server (with the native hibernate library) and all annotations follow the JPA standard. The tests led me to the same error as your code, then I set the cascade=CascadeType.ALL on both sides of the relationship and it worked. For the given error, those two entities that I submitted should suffice, but if other errors arise, / p>

Response to EDIT 3

6th Well, this problem is in relation to your method. I do not understand much of Spring (I think it is), but the logic is this:

@Transactional
    public void removeAutor(Integer autorId){

        Autor autor = autorDAO.buscarPorId(autorId);

        List<Livro> livros = autor.getLivros();

        for (Livro livro : livros) {
            System.out.println(livro.getTitulo() + " LISTA DE LIVROS ADICIONADOS");
            livro.setAutor(null);

        }

        autorDAO.remove(autor);
    }

Explaining my method

  • I get an Id ( Integer ) of my View;
  • I declare the entity and start with the method search: searchId (authorId); ;
  • I declare a list of Livro and start with the author's books: author.getLibrary ();
  • I browse this list of books and update this instance, unlinking Autor of Livro (key point);
  • I delete (delete) the searched author: autorDAO.remove (author);

Logic

  • You should search the Author entity for Id .
  • From this entity, you search the Book list.
  • This list of books you upgrade to null , with setter , done! You have unlinked Autor of those livros .
  • Then just delete the Autor , which will not erase the books.

NOTE:

  • @Transactional - does the entire transaction set automatically, so I do not need to start or close a transaction ( beginTransaction () ).
  • Your DAO structure is very limited, you must encapsulate the logic of generic DAO and use polymorphism as required by your Template . Take a look at this topic How DAO Pattern works , You'll need to better organize your code.
  • 21.12.2016 / 13:33