休眠圆形外键

时间:2010-08-18 15:48:10

标签: java hibernate spring orm

我必须测试一些我自己写过的代码。这是一个集成测试:应用程序在服务器上连续运行,我的测试针对它运行。

测试是Selenium测试,他们启动浏览器,在其中执行一些JavaScript来模拟用户操作并检查数据库是否正确更新。我必须在每次数据库之后将数据库恢复到初始状态。

要做到这一点,我通过DAO使用Spring注释和Hibernate我没有自己编写。

问题是存在循环外键。类A的对象与类型B的对象具有OneToMany关系,并且还存在具有相同类的ManyToOne关联。我尝试在同一事务中删除类型A的对象及其所有关联的B,但它不起作用因为Hibernate在删除类型A 的对象之前尝试将“defaultB”设置为null。完全没有必要使它无效,尽管删除类型B的引用对象后这样做是有意义的。

我(天真地)认为,因为2个操作是在同一个事务中执行的,所以删除类型A的对象“a”,引用(并引用)类B的对象“b”并删除b时间不会有问题。但是,我完全错了。有没有办法做到这一点而不改变数据库模型(我还没写过)?

更新1 :我不明白为什么,当我执行mySession.delete(B)时,Hibernate会尝试使一个它知道为非可空的密钥无效...对此有什么想法?

更新2 :从C类到B类之间存在一对多的关系。当我删除时,Hibernate也会尝试使对应于B的表中的“c_id”字段无效具有此c_id的C对象。即使我在它的“父”之前删除了B类的对象。我知道Hibernate重新排序查询并添加了一些自己的东西,但是我没有重新排序已经按正确顺序排列的查询以使它们失败。

这些是(相关部分)类:

@Entity
@Table(name = "A")
public class A {

    private Set<B> bs;
    private B defaultB;

    @OneToMany(mappedBy = "a", fetch = LAZY)
    public Set<B> getBs() {
        return bs;
    }

    public void setBs(Set<B> bs) {
        this.bs = bs;
    }

    @ManyToOne(fetch = LAZY, optional = false)
    @JoinColumn(name = "default_b_id", nullable = false)
    public B getDefaultB(){
        return defaultB;
    }

    public void setDefaultB(B defaultB) {
        this.defaultB = defaultB;
    }
}

@Entity
@Table(name = "B")
public class B {

    private a;

    @ManyToOne(fetch = LAZY, optional = false)
    @JoinColumn(name = "A_id", nullable = false)
    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

}

2 个答案:

答案 0 :(得分:2)

  

我尝试在同一个事务中删除A类对象及其所有关联的B

如果您不想手动删除所有B,则应该为此REMOVE级联操作。我会尝试以下方法(在两个关联上使用cascade):

@Entity
@Table(name = "A")
public class A {

    private Set<B> bs;
    private B defaultB;

    @OneToMany(mappedBy = "a", fetch = LAZY, cascade=CascadeType.REMOVE)
    public Set<B> getBs() {
        return bs;
    }

    public void setBs(Set<B> bs) {
        this.bs = bs;
    }

    @ManyToOne(fetch = LAZY, optional = false, cascade=CascadeType.REMOVE)
    @JoinColumn(name = "default_b_id", nullable = false)
    public Strategy getDefaultB(){
        return defaultB;
    }

    public void setDefaultB(B defaultB) {
        this.defaultB = defaultB;
    }
}

  

我无法更改这些注释。顺便说一句,我确实手动删除了所有关联的B,只是Hibernate问题的查询不能满足我的需求。

好的......但是我的猜测是你在删除实体之前没有正确更新双向关联的两个方面。这通常在这样的防御性编程方法中完成(在A中):

public removeFromBs(B b) {
    b.setA(null);
    this.getBs().remove(b);
}

答案 1 :(得分:0)

我假设您要删除a,但Hibernate不允许它,因为b仍然引用它?

由于元模型没有指定级联删除,因此在删除之前需要将b的链接“中断”为a。在删除。

之前,请b.setA(null)