Hibernate:使用已存在的子节点保存父对象(单向)

时间:2014-09-08 13:02:48

标签: java hibernate persistence parent-child foreign-key-relationship

我想保存/持有具有仅由父对象包含的唯一子对象的实体(父)。 任何事情都有效,直到出现重复的孩子,这里我得到以下例外:

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


首先,您必须知道我使用表达式session.bySimpleNaturalId(Child.class).load(child.getMd5Hash())来检查子项是否已存在,因为所有子对象都具有唯一的哈希值(在初始化后创建),这些哈希值明确未指定为主键(主键是自动增量; strategy = GenerationType.TABLE)。

我是否在我的DAO上使用session.merge(child)或任何其他表达式,我得到相同的例外。

我的父对象:

@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

我的孩子 - 对象:

@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


这是我保存/持久保存父项的方法(包括验证):

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


也许我并不了解整个纪录片,这就是我为什么会这样做的原因:我是否还要告诉Hibernate合并找到的实体? 我如何告诉Hibernate这些孩子不应该被视为需要坚持的新物品? 或者我甚至必须切换到双向关系?(在这种情况下我目前不允许使用双向关系)

欢迎任何提示,非常感谢,提前谢谢。 此致,Yeti

1 个答案:

答案 0 :(得分:0)

我找到了答案a.k.a我自己的错误。 首先修复它我使用了一个单独的函数来检查一个子是否存在,而且我使用了单独的会话来检查它们(如果L2C被禁用,它可能无效)。

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

第二个并且有线索,我试图将父对象保存为参数值,这是错误的,所以只需在方法中启动一个新的父对象即可。

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