【问题标题】:Can't remove child in JPA using remove() method无法使用 remove() 方法在 JPA 中删除子项
【发布时间】:2013-09-12 18:15:09
【问题描述】:

我做了相当多的研究,由于某种原因它对我不起作用这种情况)因为 remove() 没有传播到数据库中。子记录继续存在于我的数据库中。

考虑两个表:UserToken(FK_User_Id),分别是一对多关系

内部 DAO 最终代码不起作用:

public void deleteToken(Token t) {

    Token b = em.merge(t);

    em.remove(b); // does nothing

    em.flush();
}

控制器内部:

    Object obj;
    Token token;

    obj = tokenService.getByString(urlToken); // query returning detached object
    User user;

    if (obj != null) {

        token = (Token) obj; // Detached, query is "fetch" overriding lazy init, so token contains its user parent

        user = token.getUser(); // simply get the user to which this token belongs

        if ((token.getExpiryDate().compareTo(new GregorianCalendar()
                .getTime())) == 1) {

            userService.activateUser(user); // user gets merged inside and its relevant property is changed and propagated to db successfully

            tokenService.deleteToken(token); // this line calls DAO method described in snippet above - it fails to delete the token, but no error or exception - record simply stays in database

        model.addAttribute("activationSuccess", "true");


        }...

用户实体:

public class User {

    public static final String FIND_USER_BY_TOKEN = "findUserByToken";
    public static final String FIND_USER_BY_USERNAME = "findUserByUsername";
    public static final String FIND_USER_BY_EMAIL = "findUserByEmail";

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval=true)
    private List<Token> tokens = new ArrayList(); ...

令牌实体:

@Entity
@Table(name = "token")
@NamedQueries({
    @NamedQuery(name=Token.FIND_TOKEN_BY_STRING, query="Select t From Token T where t.tokenString=:string")
})
public class Token {

    public static final String FIND_TOKEN_BY_STRING = "findTokenById";
    @Id
    @GeneratedValue
    Long id;

    @ManyToOne(optional=true)
    private User user; ...

现在,如果我这样称呼:

    User c = b.getUser();
            em.remove(c);

在 DAO sn-p 内部,它会删除我不想要的令牌和用户。只有令牌必须被删除。

基本上我要做的是通过字符串属性检索 Token 以及拥有此令牌的用户父级。然后我从令牌中检索此用户并更改用户的一些属性(更改传播到数据库中)。到目前为止一切顺利。然后我想删除令牌作为最终操作,但不会删除用户。

我在第五个小时,请帮助...我设法将令牌的 setId 设置为 null(传播到数据库中),但它只会让我知道令牌不再拥有所有者但仍保留在数据库中。要删除它,我尝试将 DAO 中的 Token 与 null 合并,这引发了异常。然后我尝试在 User 中将 Tokens 列表值设置为 null (从这个令牌中检索到),它也通过我异常。

我应该如何删除与父代一起检索的子代币实体,但仍将父代保留在数据库中?

SQL Hibernate 日志显示没有删除查询...在通过 remove 方法后。

谢谢,

【问题讨论】:

  • 奇怪...一些建议:您是否尝试摆脱与用户的关系?试试看,然后问问自己是否真的需要它(可能你需要 em.remove(user))。另一方面,令牌可能保留在托管用户的已加载令牌列表中的某个位置?你用什么应用服务器?另外,您确定您查看了正确的 DB 表(应该有 Token 表,没有像 Token_User 这样的中间表)?

标签: database hibernate jpa parent-child


【解决方案1】:

如果您不从用户的令牌列表中取消引用令牌,级联持久化(您已设置包括持久化的所有级联)将导致令牌在某个时候复活。您必须清除对子项的所有引用,尤其是当您要删除实体时,标记为 cascade 的引用仍然存在。比如:

if ((token.getExpiryDate().compareTo(new GregorianCalendar()
                .getTime())) == 1) {
    user.getTokens().remove(token);
    userService.activateUser(user); 
    //tokenService.deleteToken(token); //no longer needed due to orphanremoval being true
    model.addAttribute("activationSuccess", "true");
    ...

【讨论】:

  • 是的,我在其他问题中找到了您的答案并投了赞成票,目前我已更改为 Cascade.remove,如何清除对孩子的所有引用以拥有 Cascade.ALL?只需将父用户的子列表令牌中的每个元素分配为 null?
  • 需要从集合中删除子对象,并将对它的引用设置为 null 以使您的托管对象与数据库中的内容或您想要的内容保持同步。 JPA 使引用变得容易,但它们仍然不是免费的,应谨慎使用和维护。
猜你喜欢
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 2019-03-29
  • 2020-12-13
  • 2020-11-22
  • 1970-01-01
相关资源
最近更新 更多