Cascadetype.ALL doesn’t work. Am I using it wrong?

Asked

Viewed 2,011 times

7

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

Java author.

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

Java book.

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 am using MYSQL and Hibernate 3.
I can do basic operations with this code: create, read, update and remove. But I can only delete one Autor that has no Livro related to it. When I try to delete a Autor that has Livros, get that mistake:

Cannot delete or update a Parent Row: a Foreign key Constraint fails (livros.livro, CONSTRAINT FK4607E763FA6B4EF FOREIGN KEY (autor_id) REFERENCES autor (id))

I would like that when I delete an Author who already has Related Books, they also be removed from the database. I thought the purpose of CascadeType.ALL was that, but I did not succeed using it. Where I am missing?
Thank you.

EDIT 1

Looking a little more on the internet about this problem, I came across this site. There it is said that one cannot mix JPA annotations with Hibernate (just what I was doing). I replaced @OneToMany([...], cascade = CascadeType.ALL) for @Cascade(CascadeType.ALL), but without success. Below the modified class and the delete method of my class Dao.

Java author.

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, Marcos said that you shouldn’t mix JPA with Hibernate, but that’s how I was doing it from the beginning (and it didn’t work). I looked for examples on the Internet, and my class is basically the same as all the others; the only difference is I can’t make it work. Is it possible that this is a Hibernate version problem? I use 3.5.6.

EDIT 3

As Marcos Sousa asked, here is my complete project on Github: https://github.com/mateusbandeiraa/Livros

1 answer

6


In fact,(Edition note 1: Not recommended for "mixing") do not mix notes Hibernate in JPA. to JPA is the specification and the Hibernate implements, in case of changes of implementation, for the Eclipselink for example, there would be no problems since both implement the JPA, that is to say, JPA is the standard.

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

2nd About the relationship of their entities: in cases where a Book is written by several authors? Wouldn’t it be a relationship Manytomany?

Try to update the library Hibernate, you won’t have much trouble (issue note 2: I am using Hibernate in version 5.2.3.Final).

fourth follows an auxiliary code, (issue note 3) relationship Onetomany bidirectional.

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 refactored 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 presented by your code, then I set up the cascade=CascadeType.ALL on both sides of the relationship and it worked. Porting to the error presented, these two entities I posted should be enough, but if other errors arise we will discuss more.

Response to EDIT 3

sixth Well, that’s the problem with your method. I don’t know much about Spring (I think it is), but the logic is as follows:

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

Explanation of my method

  • I get a Id (Integer) of my View;
  • I declare the entity and start with the method search: searchPorId(autorid);;
  • I declare a list of Livro and start with the author’s books: author.getLivros();
  • I go through this list of books and update this instance, untying Autor of Livro (key point);
  • do the removal (delete) of the searched author: autorDAO.remove(author);

Logic

  • You must search the entity Author for Id.
  • From this entity, you search the list of Book.
  • This list of books you update to null, with the setter, ready! you untied the Autor of those livros.
  • then just make the normal exclusion of Autor, that won’t erase the books.

NOTE:

  1. @Transactional - makes the entire transaction game automatically, so I don’t need to start or close a transaction (beginTransaction()).
  2. Its DAO structure is very limited, you should encapsulate the logic of generic DAO and use polymorphism as required by your Model. Take a look at this topic How the DAO Standard works?, Will need to organize your code better.
  • 1

    Thanks for the answer! 1. I think you reversed the titles AUTHOR & BOOK in his reply: Book has a list livros and Author has a list autores? 2. Thanks for the touch in the relationship, but it’s a simple project and I’m testing all the relationships. Many To Many has been implemented in other classes of the same project. 3. I did the test the way you sent: Book has a list of Authors & Author has a list of Books. I used the Cascade = CascadeType.ALL from JPA, but I still get the bug. Could this be version problem? I am using HIBERNATE 3.5.6

  • @Mateusflag thanks for the feed, I’m in the same line of research so we’re in the same boat. I really made a mistake in declaring variables, the code is already adjusted. vc could also, if necessary, send your configuration environment.

  • I don’t have much idea what might interfere to cause this error, but I am using Tomcat 8 and Hibernate 3.5.6-final as a dependency on Maven (hibernate-entitymanager). I put the Cascade in both classes, but the error persists. In the same project, I copied and glued its classes in full. The error persists. I believe some dependency is missing or the version I use is having some problem. I keep searching...

  • @Does Mateusflag still show the same error? how are your delete methods? post your persistence.xml and POM.xml file. how you are controlling your application’s transactions?

  • @Mateusbandeira, you can share your complete project, for me to analyze?

  • I did the test with Hibernate 4.1.1 and the problem continues. So it would hardly be a version problem... Regarding sharing the code, there is no problem; it is on Github: https://github.com/mateusbandeiraa/Livros

  • 1

    @Mateusflag, every question is the exclusion method! vc will have to "break" the relation that the entities have and from there delete the author.

  • @Mateusflag, you must take the logic of the answer and adapt to your code.

  • You’re talking about rescuing all the author’s books, and erasing them before, right? I’ve thought about it. But wouldn’t that be a scam? I’ll end up doing it anyway.

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.