2010-08-18 134 views
3

我必须测试一些我自己没有编写的代码。这是一个集成测试:应用程序在服务器上连续运行,我的测试运行在它上面。休眠循环外键

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

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

问题是存在循环外键。类A的对象与类型B的对象具有OneToMany关系,并且还存在具有相同类的ManyToOne关联。我尝试在同一事务中删除类型A及其所有关联B的对象,但它不起作用,因为在删除类型A的对象之前,Hibernate会尝试将“defaultB”设置为null。完全没有必要取消它,尽管一旦删除了类型B的引用对象就可以做到这一点。我(天真地)认为,因为在同一事务中执行了2个操作,所以删除类型A的对象“a”,该类型引用(并且引用)类B的对象“b”并且删除在同一时间将是没有问题的。但是,我显然是错误的。它有办法做到这一点而不改变数据库模型(我没有写)?我不明白为什么,当我执行mySession.delete(B)时,Hibernate试图取消它知道为非空的键......对此有何想法?

更新2:从C类到B类存在一对多的关系。当我删除C对象时,Hibernate也尝试取消对应于B的表中的“c_id”字段这个c_id。即使我删除了它的“父”之前的类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

我不是很熟悉JPA annoations但你不希望设置某种cascade'选项的'在'@ManyToOne '关系? – 2010-08-18 16:25:09

+0

Hibernate不重新排列查询以使其失败。它会根据关联对它们进行重新排序,以及您对它们做了什么以使查询成功。如果顺序错误,可能是你做了一些事情。无论如何,'defaultB'是'Bs'的成员?你可以显示你的删除逻辑? – 2010-08-19 10:37:26

回答

0

我假设你要删除,但是Hibernate不让它原因是b仍然指向它?

由于您的元模型不指定级联删除,因此您需要在删除a之前将b的链接“断开”。所以在删除之前做b.setA(null)

+0

它是不可空的,所以我不认为它会起作用。 – 2010-08-19 08:32:57

2

我尝试删除类型A的对象和它的所有相关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的手动,这只是查询休眠问题不做我想要的。

好吧......但后来我的猜测是,你不更新正确双向关系的两个双方之前删除的实体。这是在防御性编程方法通常就像这样(在A):

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

我无法更改这些注释。顺便说一句,我会删除所有关联的B的手动,这只是查询休眠问题不做我想要的。 – 2010-08-19 08:47:13

+0

为什么我会用 b.setA(null); 当'a'是不可空的? – 2010-08-23 11:40:41