0

I am trying to implement a tree referencing itself (same class) with CRUD operations using Java and Hibernate. My class is :

@Entity
@Table(name="Person")
public class Person implements Comparable<Person>{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String name;
    @ManyToOne(cascade = {CascadeType.ALL})
    private Person father;
    @OneToMany(fetch = FetchType.EAGER,  cascade = {CascadeType.ALL})
    private List<Person> children = new ArrayList<Person>();
}

Insertion works good, at each insertion I set person's father to person and add person to father's children. While deleting, if I delete the person, it complains that person id is referenced by father, if I delete father, it complains that father id is referenced by person. So, what is the correct procedure of deleting or updating? There are similar questions, but I can not find the exact explanation for this bidirectional referencing problem.

FalseScience
  • 197
  • 2
  • 17
  • Foreign key must have `ON DELETE/UPDATE CASCADE` integrity constraint to do what you want – JustMe Nov 08 '17 at 08:42
  • How can I add it? – FalseScience Nov 08 '17 at 08:49
  • 1
    As @JustMe mentioned, your error is probably at database level. You should have a look at your [foreign key definition in your database](https://www.postgresql.org/docs/9.6/static/ddl-constraints.html#DDL-CONSTRAINTS-FK). Plus, don't you want to use the [`mappedBy="..."` annotation](https://stackoverflow.com/q/11938253/4906586) in your `children` defintion? – Al-un Nov 08 '17 at 09:03
  • @FalseScience as far as I know you cannot modify `constraint on update/delete`. You must recreate the constraints accordingly like mentioned in this thread: https://stackoverflow.com/questions/10356484/how-to-add-on-delete-cascade-constraints – JustMe Nov 08 '17 at 13:53
  • @Al1 thanks for help, it made me progress:) – FalseScience Nov 09 '17 at 23:11

1 Answers1

0

So, I have found a solution to the problem thanks to @Al1's mapped byannotation. Still, after that I could not retrieve objects due to LazyInitializationException , but was able to delete the Leafs in a tree. I have fixed that issue by changing private List<Person> children= new ArrayList<Person>(); to private Collection<Person> children = new LinkedHashSet<Person>();

The class now looks like:

public class Person implements Serializable{

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    private String name;
    @ManyToOne(cascade = {CascadeType.ALL})
    private Person father;
    @OneToMany(fetch = FetchType.EAGER,  cascade = {CascadeType.ALL}, mappedBy= "father")
    private Collection<Person> children = new LinkedHashSet<Person>();
}

In order to delete the tree node, I had to to load the children by Hibernate.initialize(this.getChildren()); and then recursively delete every node. My function for deletion:

  public static String deletePerson(Person p){

        Transaction trns = null;
        Session session = HibernateUtil.buildSessionFactory().openSession();
        try {
                trns = session.beginTransaction();
                Hibernate.initialize(p.getChildren());
                if (p.hasChildren()){
                    Collection<Person> children = p.getChildren();
                    for (Person person : children) {
                        deletePerson(person);
                    } 
                    String hql = "delete from Person where name = :name";
                    session.createQuery(hql).setString("name", p.getName()).executeUpdate();
                    session.getTransaction().commit();                  
                    return "success";
                }
                else {
                    String hql = "delete from Person where name = :name";
                    session.createQuery(hql).setString("name", p.getName()).executeUpdate();
                    session.getTransaction().commit();
                    return "success";
                }


        } catch (RuntimeException e) {
            if (trns != null) {
                trns.rollback();
            }
            e.printStackTrace();
        } finally {
            session.flush();
            session.close();
        }
        return "failure";
    }

Hope this helps somebody who works with Hibernate and trees:)

FalseScience
  • 197
  • 2
  • 17