PreUpdate не срабатывает при добавлении в коллекцию

У меня есть аннотированный класс 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 и я добавляю к ней коллекцию миньонов, метод preUpdate не вызывается. В таблицу сопоставления в БД добавляется новая строка, поэтому я знаю, что происходит обновление. Если я изменяю свойство непосредственно у сотрудника, например имя, то preUpdate срабатывает, как и ожидалось, когда транзакция фиксируется.

Есть ли способ заставить PreUpdate срабатывать при изменении сопоставленной коллекции? Или есть какой-то другой метод или специальная аннотация Hibernate для обнаружения, когда это происходит?


person Adam B    schedule 23.11.2009    source источник
comment
используйте @Version — см. stackoverflow.com/a/17073342/178526   -  person sfussenegger    schedule 21.03.2019


Ответы (3)


@PreUpdate событие запускается непосредственно перед операцией ОБНОВЛЕНИЯ базы данных выполняется для рассматриваемой сущности.

Если вы не обновляете непосредственные свойства Employee, для его таблицы нет UPDATE, поэтому @PreUpdate слушатель никогда не вызывается. Вам должно повезти больше, используя событие @PrePersist, которое запускается «сбросом», а не «обновлением».

person ChssPly76    schedule 23.11.2009
comment
Вы правы. PrePersist также не помогает, так как он запускается при INSERT, и в этом случае коллекция изменяется после того, как сущность уже была сохранена. Я предполагаю, что мой вопрос действительно спрашивает, существуют ли методы, аналогичные PreUpdate, для обнаружения изменения отображаемой коллекции. - person Adam B; 24.11.2009
comment
Я не уверен, что вы подразумеваете под выстрелом в INSERT. Разве ты не звонишь entityManager.persist(employee), чтобы сохранить свою коллекцию? Если нет (например, вы полагаетесь на только сброс), вам придется настроить собственный прослушиватель для одного (или нескольких) событий сброса/автоматического сброса/флуша-сущности. (docs.jboss.org/hibernate/stable /entitymanager/reference/en/html/). Или, для решения, специфичного для Hibernate, напишите свой собственный перехватчик (docs.jboss.org/hibernate/stable/core/reference/en/html/) — всегда вызывается onFlushDirty() - person ChssPly76; 24.11.2009

Возможно, этот пользовательский обходной путь работает:

Создайте подкласс 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);
    }

    .....
}
person rabolfazl    schedule 21.05.2011

Вот моя реализация для провайдера Hibernate:

http://pastebin.com/8cPB96bZ

Обычно вы просто отмечаете методы, которые следует вызывать в случае грязной коллекции, с помощью аннотации @PreCollectionChange.

person Mikhail Kadan    schedule 05.08.2014
comment
Всегда полезно включать операторы импорта, чтобы в любом случае можно было определить, какой именно импорт необходим. В данном случае у меня есть откуда вы взяли ReflectionUtils. В настоящее время я думаю, что во многих сторонних библиотеках есть класс с именем ReflectionUtils. - person alexander; 26.04.2021