一对多的JPA注释不会删除孤儿

时间:2009-11-14 22:51:08

标签: java unit-testing hibernate orm jpa

我正在尝试构建用户和联系人管理项目。 我有很多课程,所以将它限制在这里所关注的内容。我有userAccount,userProfile和group 这是UserAccount Mapping

@Id @GeneratedValue
@Column(name="USER_ACCOUNT_ID")
private Long ID; 
 ......
 @Column(name="EMAIL", length=100, unique=true)
private String email;

@OneToOne(targetEntity=UserProfileImpl.class,cascade={CascadeType.ALL})
 @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@JoinColumn(name="USER_PROFILE_ID")
private UserProfile profile;

 @OneToMany(targetEntity=GroupImpl.class, cascade={CascadeType.ALL})
 //    @JoinColumn(name="USER_ACCOUNT_ID")
@JoinTable(name = "USER_ACCOUNT_CONTACT_GROUP", joinColumns = @JoinColumn(name = "USER_ACCOUNT_ID"), inverseJoinColumns = @JoinColumn(name = "GROUP_ID"))
@org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Group> groups = new HashSet<Group>();
........

这是userProfile

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="USER_PROFILE_ID")
private Long ID;
.....
 @OneToOne(mappedBy="profile", targetEntity=UserAccountImpl.class)
private UserAccount userAccount;
.....

这是小组

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="GROUP_ID")
private Long ID;    
.......
@Column(name="NAME", length=100, unique=true)
private String Name;

@ManyToOne(targetEntity=UserAccountImpl.class)
@JoinColumn(name="USER_ACCOUNT_ID",nullable=false)
private UserAccount userAccount;

所以基本上就是这样。在进行测试之前,将userAccount对象添加到group.so之前,一切都很顺利。我创建userProfile,userAccount和group(使用spring @autowired) 在setUP(@Before)方法中,我将几个prop设置为userProfile并将其添加到useAccount及其prop并将其保留,然后将useAccount设置为该组。
在tearDown(@After)上我删除了userACcount 在我的testSave(保存组)工作正常(对所有操作使用相同的会话)但在控制台上没有删除sql查询组,但它删除userAccount虽然。
通过删除拆解方法中的userAccount,我希望将组删除到。但事实并非如此。
更糟糕的是因为对该组名称的独特限制,其他测试令人心惊。我在网上搜索但我尝试的一切似乎都不起作用。谁能救我:)?我的意思是我应该怎么做?感谢您的阅读

这是我根据我的反应尝试过的更新。 我已将此group.setUserAccount(null)添加到我的removeGroup,现在是

public void removeGroup(Group group) {
    try{
       if(this.groups.contains(group)){
        group.setUserAccount(null);
        this.groups.remove(group);
       }
    } catch(Exception ex){
        ex.printStackTrace();
    }
}

所以对于我使用的具有相同行为的测试,即删除userAccount但不删除组

ua1.removeGroup(g1);
uaDao.delete(ua1);

我猜它不会进入if块,因为我应该有与此相同的行为:

 g1.setUserAccount(null);
 uaDao.delete(ua1);

另一个抛出错误

  

PropertyValueException:not-null属性引用空值或瞬态值

所以我想我会删除该群组:

gDao.delete(g1);
uaDao.delete(ua1);

希望我找到一种方法来解决它。感谢那些帮助我的人,特别是Pascal,如果你有另一个想法或者发现我的代码有问题,我会非常乐意纠正它。谢谢读

2 个答案:

答案 0 :(得分:2)

首先关闭UserAccount - &gt; Group关系是双向的,那么您需要将反向收集方面映射为

@OneToMany(targetEntity=GroupImpl.class, cascade{CascadeType.ALL},mappedBy="userAccount")

所以现在Hibernate知道UserAccount是集合的所有者。现在要删除@Pascal说你需要解开双方。由于Hibernate忽略了集合,所以所有者负责绑定关系,所以基本上像这样的辅助方法在UserAccount

中创建关联
public void addGroup(Group group){
     group.setUserAccount(this);
     groups.add(group);
}

现在删除另一个辅助方法

public void removeGroup(Group group){
    group.setUserAccount(null);
    groups.remove(group);
}

现在要删除

UserAccount ua = //load user account object
for(Group g : ua.getGroups())
      ua.removeGroup(g);

session.delete(ua);

您的代码现在应该可以使用了。你不必按照我的方式去做,但我希望你得到漂移。DELETE_ORPHAN应该照顾你的级联删除groups

答案 1 :(得分:1)

使用@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)很好但是......

您是否还要将userAccount中的Group引用设置为null

您仍然需要手动管理Java关系,例如,如果关系是双向的,则必须将父级设置为null