【问题标题】:How to update the list after delete an item of that list删除该列表的项目后如何更新列表
【发布时间】:2011-06-01 23:24:39
【问题描述】:

我需要一点时间来解释这一点,所以请和我在一起。我有表 NewsFeed 与自身具有 OneToMany 关系。

@Entity
public class NewsFeed(){
    ...
    @ManyToOne(optional=true, fetch=FetchType.LAZY)
    @JoinColumn(name="REPLYTO_ID")
    private NewsFeed replyTo;

    @OneToMany(mappedBy="replyTo", cascade=CascadeType.ALL)
    private List<NewsFeed> replies = new ArrayList<NewsFeed>();

    public void addReply(NewsFeed reply){        
       replies.add(reply);
       reply.setReplyTo(this);
    }

    public void removeReply(NewsFeed reply){
       replies.remove(reply);
    }
} 

所以你可以这样想。每个提要都可以有一个List 的回复,这些回复也是NewsFeed 类型。现在我很容易删除原始提要并取回更新的列表。删除后我需要做的就是这个。

feeds = scholarEJB.findAllFeed();  //This will query the db and return updated list

但我在尝试删除 replies 并取回更新后的列表时遇到问题。所以这就是我删除replies 的方法。在我的 JSF 托管 bean 中,我有

//Before invoke this method, I have the value of originalFeed, and deletedFeed set.
//These original feeds are display inside a p:dataTable X, and the replies are
//displayed inside p:dataTable Y which is inside X. So when I click the delete button
//I know which feed I want to delete, and if it is the replies, I will know
//which one is its original post
public void deleteFeed(){
    if(this.deletedFeed != null){
        scholarEJB.deleteFeeds(this.deletedFeed); 
        if(this.originalFeed != null){
            //Since the originalFeed is not null, this is the `replies`
            //that I want to delete
            scholarEJB.removeReply(this.originalFeed, this.deletedFeed);
        }
        feeds = scholarEJB.findAllFeed();
    }        
}

然后在我的 EJB 学者EJB 里面,我有

public void removeReply(NewsFeed feed, NewsFeed reply){
    feed = em.merge(feed);
    comment.removeReply(reply);
    em.persist(comment);
}

public void deleteFeeds(NewsFeed e){
    e = em.find(NewsFeed.class, e.getId());
    em.remove(e);
    em.getEntityManagerFactory().getCache().evict(NewsFeed.class); //Like fdreger suggested
}

当我离开时,实体(回复)会从数据库中正确删除,但在 feeds 列表中,reply 的引用仍然存在。直到我注销并重新登录,回复才会消失。

【问题讨论】:

    标签: java jpa


    【解决方案1】:

    您所写的是正确的,重新查询应该可以工作(实际上通常是这样),所以问题一定出在其他地方。例如,如果您通过 remove 方法以外的任何方式删除实体,它可能仍位于 2 级缓存中。或者可能因为一些小错误而根本没有重新查询?


    更新:在阅读了原始问题的新版本(包括所有新来源和关于 Eclipselink 的说明)后,我做了一个小测试,它确实是一个二级缓存问题。有点奇怪,可能是错误或未指定的极端情况。要修复它,请从缓存中驱逐 cmets:

    // this goes after em.remove(e)
    em.getEntityManagerFactory().getCache().evict(Comment.class);
    

    您也可以尝试仅驱逐已删除实体的父级(驱逐的重载版本)。

    嗯。也许有更多街头信誉的人(BalusC?:-) 应该更改这篇文章的标签。原来它与JSF无关。

    【讨论】:

    • 谢谢。我通过remove 方法删除了实体。如果我删除原始帖子,那么效果很好。实体被删除,列表重新更新。不知道为什么它不适用于回复。你能多谈谈二级缓存吗?
    • 这要么是您的 JPA 实现中的一个主要错误(从惰性的使用来看,它可能是 eclipselink - 是吗?),或者是 Primefaces 中的一个主要错误,或者是您的应用程序中的一个小错误。尝试调试(for 循环中的几个 out.printlns 即可)从 myEJB.getAllComments 返回的值。这样你会知道:1)如果方法被调用,2)如果返回的数据看起来很好(我的拍摄是它根本没有被调用)
    • 是的,它是eclipselink,我会照你说的做。一会儿回来
    • 好吧,我用调试器检查,重新查询的方法确实被调用了。另外,如果我删除原始帖子,那么它可以正常工作。这让我发疯。天哪,这是新的一年,我坚持这个问题。看起来如此微不足道,为什么它不起作用:(
    • 关于在 JPA 中驱逐单个实体的警告说明:em.getEntityManagerFactory().getCache().evict(Comment.class);。这是一个相当不安全的操作,因为它可能会使缓存处于不一致的状态。现在可能存在对未缓存对象的悬空引用。如果您需要进行驱逐,请使用 evictAll,这是安全的。
    【解决方案2】:

    当您删除一个对象时,您必须先删除对该对象的所有引用,然后再删除它。如果不这样做,您可能会在持久性上下文或二级缓存中收到约束错误或陈旧数据。

    删除 Feed 时,请先将其从回复中删除。

    【讨论】:

    • 这也可能是我的问题。如果你看看我的代码。实际上,我首先删除了提要,然后将其从回复中删除。你是说如果我翻转订单,它就会起作用。现在,我使用 fdreger 的建议,并驱逐二级缓存。它现在可以工作。但也很高兴知道是否有其他方法可以做到这一点
    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 2019-01-26
    • 2018-01-14
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多