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

Posted

技术标签:

【中文标题】一对多 JPA 注释不会删除孤儿【英文标题】:one-to-many JPA annotations won't delete orphans 【发布时间】:2009-11-14 22:51:08 【问题描述】:

我正在尝试构建一个用户和一个联系人管理项目。 我有很多课程,所以将其限制在此处关注的内容。我有一个 userAccount、userProfile 和 group 这是 UserAccount 映射

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

所以基本上就是这样。在进行双向关联之前,一切都很顺利,将 userAccount 对象添加到 group.so 进行测试。我创建了 userProfile、userAccount 和组(使用 spring @autowired)。 在 setUP (@Before) 方法上,我为 userProfile 设置了一些道具,并将其与道具一起添加到 useAccount 并持久化,然后将 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:非空属性引用空值或瞬态值

所以我想我会使用删除组:

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

希望我能找到解决方法。感谢帮助我的人,尤其是 Pascal,如果您有其他想法或发现我的代码有问题,我将非常乐意纠正它。谢谢阅读

【问题讨论】:

提供更多线索。我隔离了 testSave 方法并注释掉所有其余的方法。当我在拆解中对 userAccount 调用 delete 时,它​​会删除用户帐户和 userProfile 但不是组。所以我删除了首先在删除 UserAccount 中的组,然后那个也可以正常工作。但我不应该删除组,我只想删除将删除组的 userAccount。谢谢 【参考方案1】:

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

@OneToMany(targetEntity=GroupImpl.class, cascadeCascadeType.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 的级联删除

【讨论】:

感谢 bruv 我明白了。我不知道我确实有 removeGroup 但没有将 userAccount 设置为 null 广告不知道必须在删除之前调用它userAccount。非常感谢 我更新了我的帖子。它不影响结果。它是同一件事 您是否将mappedBy=userAccount 包含在@OneToMany 中? 是的。我认为这是因为 UserAccount 不能为空 @JoinColumn(name="USER_ACCOUNT_ID",nullable=false) 。这就是我的想法,但不确定,因为没有所有者就无法退出组,所以我现在有点困惑。感谢您的响应【参考方案2】:

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

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

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

【讨论】:

我不知道你能不能详细说明一下?谢谢。所以在我保存孩子之前,我保存了父母,像这样group.setUserAccount(userAccount)在孩子中设置父母,然后保存孩子。所以如果我让你正确地让我的场景发生,即删除父母级联到孩子(删除孩子),我必须设置group.setUserAccount(null);是你说的吗?感谢阅读并感谢您的回答 感谢 Pascal。你再次帮助了我。谢谢,基本上我所有关于休眠的知识都来自***。

以上是关于一对多 JPA 注释不会删除孤儿的主要内容,如果未能解决你的问题,请参考以下文章

更新一对多关系后删除孤儿

JPA @ElementCollection 注释是不是总是产生一对多的关系?

使用 H2、JPA 注释和 Hibernate 问题的一对多关联

休眠一对多关联删除

一对多映射不起作用Spring数据JPA

jpa休眠一对多双向[重复]