【问题标题】:PreUpdate not firing when adding to a collection [duplicate]添加到集合时不触发 PreUpdate [重复]
【发布时间】:2009-11-23 21:59:41
【问题描述】:

我有一个 JPA 注释类,其中包含这样的集合:

@Entity
public class Employee {
    @Id
    private int id; 
    @Basic
    private String name;    
    @OneToMany
    @JoinTable(name = "ORG", joinColumns = @JoinColumn(name="MINION"),
        inverseJoinColumns = @JoinColumn(name="EMP"))
    private List<Employee> minions = new ArrayList<Employee>();

    @PreUpdate
    public void preUpdate(){ ... }
}

我看到的是,如果我有一个托管的 Employee 实体并且我添加到它的 minions 集合中,则不会调用 preUpdate 方法。数据库中的映射表中添加了一个新行,因此我知道更新正在进行中。如果我直接更改 Employee 上的属性,例如姓名,那么preUpdate 会在事务提交时按预期触发。

有没有办法让 PreUpdate 在映射集合被修改时触发?或者是否有其他技术或 Hibernate 特定注释来检测何时发生这种情况?

【问题讨论】:

标签: java hibernate orm jpa


【解决方案1】:

@PreUpdate 事件在为相关实体执行 database UPDATE operation 之前触发。

如果您不更新Employee 的直接属性,则没有要为其表执行的UPDATE,因此永远不会调用@PreUpdate 侦听器。使用由“flush”而不是“update”触发的@PrePersist 事件应该会有更好的运气。

【讨论】:

  • 你是对的。 PrePersist 也无济于事,因为它是在 INSERT 上触发的,在这种情况下,在实体已经持久化之后会修改集合。我想我的问题实际上是在问是否有类似于 PreUpdate 的技术来检测映射集合何时被修改。
  • 我不确定您所说的“在插入时触发”是什么意思。你不是打电话给entityManager.persist(employee) 来保存你的收藏吗?如果你不是(例如你依赖于flush only)你将不得不为一个(或多个)“flush”/“auto-flush”/ “刷新实体”事件 (docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/…)。或者,对于特定于 Hibernate 的解决方案,编写自己的拦截器 (docs.jboss.org/hibernate/stable/core/reference/en/html/…) - 始终调用 onFlushDirty()
【解决方案2】:

也许这种自定义解决方法有效:

创建一个 ArrayList 的子类,通过 ActionListener 模式识别变化

public class Employee {
    ....

    private List<Employee> minions = createChangeNotifierList();

    private List<Employee> createChangeNotifierList() {
        ChangeNotifierList<Employee> l = new ChangeNotifierList<Employee>();
        l.setActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                preUpdate();
            }
        });
        return l;
    }

    public void setMinions(List<Employee> l) {
        if (!(l instanceof ChangeNotifierList)) {
            l = createChangeNotifierList();
            preUpdate();
        }
        this.minions = l;
    }

    public void preUpdate(){ ... }
}


public class ChangeNotifierList<T> extends ArrayList<T> {

    private ActionListener actionListener;

    public ChangeNotifierList() {
    }

    public ChangeNotifierList(List<T> list) {
        super.addAll(list);
    }

    public void setActionListener(ActionListener actionListener) {
        this.actionListener = actionListener;
    }

    public boolean add(T e) {
        boolean b = super.add(e);
        if (b) {
            notifyChange();
        }
        return b;
}

    private void notifyChange() {
        actionListener.actionPerformed(null);
    }

    .....
}

【讨论】:

    【解决方案3】:

    这是我对 Hibernate 提供程序的实现:

    http://pastebin.com/8cPB96bZ

    通常,您只需使用 @PreCollectionChange 注释标记在脏集合的情况下应调用的方法。

    【讨论】:

    • 包含导入语句总是一个好主意,因此在任何情况下都可以确定确切需要哪个导入。在这种情况下,我知道您从哪里获取 ReflectionUtils。现在,我认为许多第三方库都有一个名为 ReflectionUtils 的类
    猜你喜欢
    • 2014-05-11
    • 1970-01-01
    • 2010-12-13
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多