Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA delete fails (integrity constraint violation: foreign key no action) - data model too convoluted?

I'm experiencing a problem I cannot get my head around. I really hope someone out there can help.

Entity model

This might get a little meta as my data model represents programming objects. I've got three entities: Program, Clazz and Method. Classes can have multiple methods and occasionally inherited some other methods (from other classes).

@Entity
public class Program {

    @OneToMany(mappedBy="program", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @OrderBy("name ASC")
    private Set<Clazz> clazzes = new TreeSet<Clazz>();
}

@Entity
public class Clazz {

    @ManyToOne
    private Program program;

    @OneToMany(mappedBy="clazz", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @OrderBy("name ASC")
    private Set<Method> methods = new TreeSet<Method>();

    @ManyToMany(fetch=FetchType.LAZY, mappedBy="inheritedBy")
    @OrderBy("name ASC")
    private Set<Method> inheritedMethods = new TreeSet<Method>();

    @PreRemove
    private void tearDown() {
        inheritedMethods.clear();
    }

}

@Entity @Table(name="sf_method")
public class Method {

    @ManyToOne(optional=true)
    private Clazz clazz;

    @ManyToMany(fetch=FetchType.LAZY)
    @JoinTable(name = "sf_method_inherited_by_class", 
        joinColumns = { @JoinColumn(name = "sf_method_inherited_by_class") }, 
        inverseJoinColumns = { @JoinColumn(name = "sf_class_inherits_method") }
    )
    private Set<Clazz> inheritedBy = new HashSet<Clazz>();

    @PreRemove
    public void tearDown() {
        inheritedBy.clear();
    }

}

My problem: what I do

What I need to do is to delete a program, including all its classes and methods. I use Spring-JPA repositories, so my code is:

@Autowired ProgramRepository programs;

@Transactional(readOnly=false)
public void forceDelete(Program p) {
    Set<Clazz> myClasses = p.getClazzes();
    for (Clazz c : myClasses) {
        logger.info("Clazz " + c.getName());
        for (Method m : c.getMethods()) {
            m.setClazz(null);
            methods.save(m);
        }
    }
    programs.delete(p);
}

What happens

The delete code works only in some circumstances. Sometimes I get the following error.

SqlExceptionHelper - integrity constraint violation: foreign key no action; FKIBMDD2FV8TNJAF4VJTOEICS73 table: SF_METHOD AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements

Any idea? I spent so many hours on this and I failed every single resolution attempt. What am I doing wrong?

like image 861
Lorenzo Frattini Avatar asked Oct 31 '22 18:10

Lorenzo Frattini


1 Answers

Here you are trying to delete the parent without deleting the child which have foreign key referencing to the parent.

Here, before you delete p you have to delete children for p. You can get that by : p.getClazzes();

Again before deleting Clazz, you have to delete children for it(in this case, Method) as above...

like image 70
DMajumdar Avatar answered Nov 02 '22 09:11

DMajumdar