代码之家  ›  专栏  ›  技术社区  ›  black sensei

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

  •  0
  • black sensei  · 技术社区  · 16 年前

    我正在尝试建立一个用户和联系人管理项目。 我有很多课程,所以会把它限制在这里所关注的范围内。我有一个用户帐户、用户配置文件和组 这是用户帐户映射

    @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>();
    ........
    

    这是用户配置文件

    @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;
    

    所以基本上就是这样,在a进行双向关联将useraccount对象添加到group.so测试之前,一切都很好。我创建用户配置文件、用户帐户和组(使用spring@autowired)。
    在设置(@before)方法中,我将少数prop设置为userprofile,并将其与prop一起添加到useaccount,并将其持久化,然后将useaccount设置为组。
    在拆卸(@after)时,我删除了用户帐户。
    在我的testsave上(保存组)工作正常(对所有操作使用相同的会话),但是在控制台上没有针对组的删除SQL查询,但是它会删除用户帐户。
    通过删除teardown方法中的用户帐户,我希望可以将组删除到,但事实并非如此。
    更糟糕的是,由于对组名的唯一限制,其他测试都失败了。我在网上搜索,但我所尝试的一切似乎都不起作用。谁能救我:)?我是说我该怎么做?谢谢你的阅读

    这是我根据自己的反应所做的更新。 我已将此添加到 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();
        }
    }
    

    因此,对于我使用的具有相同行为的测试,即删除用户帐户,但不删除组

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

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

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

    另一个抛出错误

    PropertyValueException:非空属性引用了空值或临时值

    所以我想我会用以下方法删除这个组:

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

    希望我能找到解决方法。感谢那些帮助过我的人,特别是帕斯卡,如果你有其他想法或发现我的代码有问题,我会非常乐意纠正它。谢谢你的阅读。

    2 回复  |  直到 16 年前
        1
  •  2
  •   non sequitor    16 年前

    首先,如果 UserAccount -gt; Group 关系是双向的,那么您需要将反向收集端映射为

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

    所以现在Hibernate知道 用户帐号 是集合的所有者。如@pascal所说,现在删除时需要解除两边的绑定。因为Hibernate忽略了集合,所以所有者负责绑定关系,所以基本上像这样的助手方法在 用户帐号

    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

        2
  •  1
  •   Pascal Thivent    16 年前

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

    你也在设置 userAccount 中的引用 Group null ?

    您仍然需要手动管理Java关系,即必须设置父 无效的 在儿童中,如果关系是双向的。