休眠:从列表中删除项目不会保留

时间:2009-02-14 23:13:44

标签: java hibernate

从列表中删除项目时遇到问题。该列表在超类中定义,但Hibernate注释应用于子类中的属性访问器。超类中有两种方法可以操作列表。 “添加”方法工作正常,但“删除”不会持续更改。我检查了我的Cascade设置,我似乎有正确的事情。我做的事情是不可能的。如果没有,我做错了吗?

以下是我的课程:

@Entity 
abstract class Temporal<T> { 
    @Id 
    @GeneratedValue 
    private Long id; 

    @Version 
    private Integer version = null; 

    @Transient 
    protected List<T> content = new ArrayList<T>(); 

    public void remove(T value) { 
        // business logic ... 
        content.remove(value); 
    } 

    public void add(T value) { 
        // business logic ... 
        content.add(value); 
    } 
} 

@Entity 
@AccessType("property") 
class TemporalAsset extends Temporal<Asset> { 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "temporal") 
    public List<Asset> getContent() { 
        return super.content; 
    } 

    protected void setContent(List<Asset> list) { 
        super.content = list; 
    } 
} 

我使用TemporalAsset类的实例如下(请注意,我只使用“refresh”方法来演示行为。即使我刷新或关闭会话并打开新会话,列表也不会正确保留) :

temporalAsset.add(value1); 
temporalAsset.getContent().size() == 1; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 1; // true 

temporalAsset.remove(value1); 
temporalAsset.getContent().size() == 0; // true 
session.update(temporalAsset); 

session.refresh(temporalAsset); 

temporalAsset.getContent().size() == 0; // false, its 1 

感谢。

4 个答案:

答案 0 :(得分:19)

您必须将Cascade显式指定为CascadeType.DELETE_ORPHAN。

尝试将代码更改为

@OneToMany    
@Cascade(cascade = {CascadeType.ALL, CascadeType.DELETE_ORPHAN}, mappedBy = "temporal")

部分来自休眠docs

  

如果子对象的生命周期是   受到父母生命的限制   对象,让父母充满   生命周期对象通过指定   CascadeType.ALL和   org.hibernate.annotations.CascadeType.DELETE_ORPHAN   (请参考Hibernate   语义参考指南   孤儿删除)

答案 1 :(得分:1)

尝试删除对Session.refresh()的调用。来自文档:

  

重新阅读给定的状态   来自底层数据库的实例。   不建议使用它   实现长期运行的会话   跨越许多业务任务。这种方法   然而,在某些特殊情况下是有用的   情况。例如

     
      
  • 数据库触发器在插入或更新时更改对象状态
  •   
  • 在同一会话中执行直接SQL(例如,批量更新)后
  •   插入Blob或Clob后
  •   

http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#refresh(java.lang.Object)

如果在refresh()之前调用flush(),那也可能解决问题,因为flush()保证将对数据库执行任何挂起的SQL。在实践中,我几乎从未见过任何人使用refresh(),它看起来与您需要的代码不同。

本章的文档值得一读:

http://www.hibernate.org/hib_docs/v3/reference/en/html/objectstate.html

答案 2 :(得分:0)

您已在超类中将'content'字段标记为瞬态。我至少会怀疑这会造成问题。通过子类中的映射,您现在基本上具有两个相同属性的矛盾映射。

答案 3 :(得分:0)

这是当前推荐的方法。

@OneToMany(mappedBy = "temporal", orphanRemoval = true, cascade = CascadeType.ALL)