【问题标题】:Hibernate: Removing item from a List does not persist休眠:从列表中删除项目不会持续存在
【发布时间】:2009-02-14 23:13:44
【问题描述】:

从列表中删除项目时遇到问题。该列表在超类中定义,但 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 类的实例如下(请注意,我只使用“刷新”方法来演示该行为。即使我刷新或关闭会话并打开一个新会话,该列表也不会正确保留) :

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 

谢谢。

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

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

    尝试将代码更改为

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

    部分来自休眠docs:

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

    【讨论】:

    【解决方案2】:

    这是目前推荐的方式。

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

    【讨论】:

      【解决方案3】:

      尝试删除对 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

      【讨论】:

      • 我在这里只包括了刷新来演示行为。实际上,刷新不会将更改保留到列表中。我什至可以关闭会话,打开一个新会话,列表中仍然有值。
      【解决方案4】:

      您已在超类中将“内容”字段标记为瞬态。我至少会怀疑这会导致问题。使用子类中的映射,您现在基本上对于同一属性有两个相互矛盾的映射。

      【讨论】:

      • 你会想,但这不会造成任何问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-16
      • 1970-01-01
      • 2019-03-17
      • 2013-11-28
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      相关资源
      最近更新 更多