Hibernate, однонаправленный ManyToOne и стремление к функции «При удалении каскада» - PullRequest
1 голос
/ 05 декабря 2011

У меня есть проблема, которая равна представленной здесь: как определить обратное каскадное удаление при отображении "многие к одному" в спящем режиме

После поиска я не могу найти достойное / чистое решение для этого. У меня не может быть родительской сущности, которая имеет @OneToMany для дочернего объекта, потому что они находятся в разных модулях. Я хотел попробовать EntityListener, который удалял бы дочерние элементы до того, как появился родительский, но я не могу, потому что, опять же, они находятся в разных модулях.

Кто-нибудь знает чистое решение для этого? Я подумываю использовать AspectJ для прослушивания вызова метода delete из ParentDao, но это не чистое решение, и мне придется реализовать его для каждой сущности, имеющей такой тип связи с классом Parent.

Этот вид каскада, кажется, является основной функцией, и я немного разочарован, увидев, что hibernate не поддерживает его: /

Ответы [ 2 ]

2 голосов
/ 05 декабря 2011

Ответ на вопрос, на который вы ссылаетесь, правильный. Hibernate может удалять потомков только при удалении родителя, если родитель знает о своих потомках.

Единственное решение - использовать метод delete ParentDAO для поиска всех дочерних элементов родителя, удаления их, а затем удаления самого родителя.

Если вы обеспокоены тем, что ParentDAO не должен знать о дочерних элементах, вы можете отключить его, и у ParentDAO будет список зарегистрированных ParentDeletionListeners, который будет вызван перед удалением самого родителя. ParentDAO знает только об этом интерфейсе ParentDeletionListener и позволяет зарегистрировать несколько слушателей. При запуске приложения зарегистрируйте слушателя для каждого типа ребенка и попросите его удалить дочерние элементы:

public interface ParentDeletionListener {
    void parentWillBeDeleted(Parent parent);
}

public class SomeChildParentDeletionListener implements ParentDeletionListener {
    // ...
    public void parentWillBeDeleted(Parent parent) {
        // search for every SomeChild linked to the given parent
        // and delete them
    }
}

public class ParentDAO {
    private List<ParentDeletionListener> listeners = new CopyOnWriteArrayList();

    public void addParentDeletionListener(ParentDeletionListener listener) {
        this.listeners.add(listener);
    }

    public void deleteParent(Parent p) {
        for (ParentDeletionListener listener : listeners) {
            listener.parentWillBeDeleted(parent);
        }
        session.delete(parent);
    }
}
1 голос
/ 06 декабря 2011

Основываясь на ответе JB Nizet, я изменил свой DAO, чтобы иметь DeleteOperationListener (Моя базовая реализация DAO основана на «Не повторять DAO» [1].) Таким образом, у меня есть универсальное решение на случай, если я окажусьв той же ситуации снова.Структура выглядит следующим образом:

public interface GenericDao<T, PK extends Serializable> {
    // CRUD methods

    // delete operation listeners.
    void addDeleteListener(DeleteOperationListener<T, PK> deleteOperationListener);

    public interface DeleteOperationListener<T> {
        void preDelete(T entity);
        void posDelete(T entity);
    }
}

И моя абстрактная hibernate-реализация позволяет уведомлять наблюдателей об удалении.

@Override
public void delete(T entityToDelete) {
    notifyPreDelete(entityToDelete);
    this.getHibernateTemplate().delete(entityToDelete);
    notifyPosDelete(entityToDelete);
}

А теперь у меня есть другой класс, который обрабатывает удалениедети без необходимости менять DAO:

@Service
public class ParentModificationListener
    implements GenericDao.DeleteOperationListener<Parent> {

    private ChildDao childDao;

    @Autowired
    public ParentModificationListener(ChildDao childDao, ParentDao parentDao) {
        this.childDao = childDao;
        parentDao.addDeleteListener(this);
    }

    @Override
    public void preDelete(Parent parent) {
        this.childDao.deleteChildrenFromParent(parent);
    }

    @Override
    public void posDelete(Parent parent) {
        // DO NOTHING
    }
}

[1] http://www.ibm.com/developerworks/java/library/j-genericdao.html

...