2

I want to save/persist an entity(parent) with unique children objects included only by the parent object. Anything works well until a duplicate child appears, here I get following Exception:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry


At first you have to know that I'm using the expression session.bySimpleNaturalId(Child.class).load(child.getMd5Hash()) to check if the child already exists, because all children objects have unique hash values(created after initializing) which are explicitly not assigned as the primary key(their primary key is an auto-increment; strategy = GenerationType.TABLE).

Whether I use session.merge(child) or any other expression on my DAO, I get the same exception.

My Parent-Object:

@Entity
@Table(name = "parent")
public class Parent implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id = null;


    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "kind_child_id", referencedColumnName = "md5hash")
    private Child firstChild;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "rude_child_id", referencedColumnName = "md5hash")
    private Child secondChild;

    //private String attributes;
    //Getters & Setters

My Child-Object:

@Entity
@Table(name = "child")
public class Child implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.TABLE)
        private Long id = null;

        @NaturalId
        @Column(name="md5hash", unique=true)
        private char[] md5hash = new char[32];

        //private String attributes;
        //Getters & Setters


And here is my method to save/persist a parent(validations included):

public void writeParent(Parent parent) {
                try {
                    if (parent != null) {
                        if (globalSession == null) {
                            globalSession = getSessionFactory().openSession();
                        }
                        globalSession.beginTransaction();

                            if (parent.getFirstChild() != null) {
                                Child tempFirstChild = (Child)  globalSession.bySimpleNaturalId(Child.class).load(parent.getFirstChild().getMd5Hash());
                                if (tempFirstChild != null) {
                                    parent.setFirstChild(tempFirstChild);
                                    //globalSession.merge(tempFirstChild);
                                    //throws MySQLICV-Exception

                                    //globalSession.update(tempFirstChild);
                                    //throws MySQLICV-Exception
                                }
                            }
                            if (parent.getSecondChild() != null) {
                                Child tempSecondChild = (Child) globalSession.bySimpleNaturalId(Child.class).load(parent.getSecondChild().getMd5Hash());
                                if (tempSecondChild != null) {
                                    parent.setSecondChild(tempSecondChild);

                                    //globalSession.merge(tempSecondChild);
                                    //throws MySQLICV-Exception

                                    //globalSession.update(tempSecondChild);
                                    //throws MySQLICV-Exception

                                }
                            }

                        globalSession.saveOrUpdate(parent);
                        //globalSession.persist(parent);
                        globalSession.getTransaction().commit();
                    }
                } catch (Exception ex) {
                    log.error("FAILURE: ", ex);
                }
finally{
globalSession.close();
}
            }


Maybe I didn't understand the entire documentary that's why I came up for this: Do I even have to tell Hibernate to merge the found entities? How can I tell Hibernate that those children shouldn't be treated as new objects which need to be persisted? Or do I even have to switch to bidirectional relations?(I'm currently not allowed to use bidirectional relations in this case)

Any hints are welcome and very appreciated, thank you in advance. Regards, Yeti

Yeti
  • 63
  • 7
  • Well let me understand, why are you in the first place try to update or save the child object, as you are associating those with the parent and you are saving/updating the parent, they would anyway be persisted? – ajay.patel Sep 08 '14 at 15:10
  • @zerocool Of course they will be persisted anyways, those methods you're referring to are just for testing operations, cause it might be possible that I want to modify some attributes of a child. – Yeti Sep 09 '14 at 10:23

1 Answers1

0

I found the answer a.k.a the mistake myself. At first to fix it I used a separate function to check if a child exists, furthermore I used separate sessions to check them(maybe it doesn't work if L2C is disabled).

synchronized public Child checkChild(Child child) {
    try {
        if (child != null) {
            tempSession = getSessionFactory().openSession();
            Child tempChild = (Child) tempSession.bySimpleNaturalId(Child.class).load(Child.getMd5Hash());
            if (tempChild != null) {
                return tempChild;
            } else {
                return child;
            }
        } else {
            return null;
        }
    } catch (Exception ex) {
        return null;
    }
    finally{
        tempSession.close();
    }
}

At second and there is the clue, I tried to save the parent object as the parametrical value, which is wrong, so just initiate a new parent-object within the method and it's done.

public void writeParent(Parent parent) {
    tempParent = new Parent();
    tempParent.setFirstChild(checkChild(tempParent.getFirstChild()));
    tempParent.setSecondChild(checkChild(tempParent.getSecondChild()));
    globalSession = getSessionFactory().openSession();
    globalSession.beginTransaction();
    globalSession.saveOrUpdate(tempParent);
    globalSession.getTransaction().commit();
    globalSession.close();
}
Yeti
  • 63
  • 7