Hibernate: удаление элемента из списка не сохраняется - PullRequest
13 голосов
/ 15 февраля 2009

У меня проблемы при удалении элемента из списка. Список определен в суперклассе, но аннотации Hibernate применяются к методам доступа к свойствам в подклассе. В суперклассе есть два метода, которые управляют списком. Метод «add» работает нормально, но «remove» не сохраняет изменений. Я проверил свои настройки 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 

Спасибо.

Ответы [ 3 ]

19 голосов
/ 15 февраля 2009

Вы должны явно указать каскад как CascadeType.DELETE_ORPHAN.

Попробуйте изменить код на

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

Деталь из спящего режима Документы :

Если срок службы дочернего объекта ограничено продолжительностью жизни родителя объект, сделать родителя полным объект жизненного цикла, указав CascadeType.ALL и org.hibernate.annotations.CascadeType.DELETE_ORPHAN (пожалуйста, обратитесь к Hibernate справочник по семантике сирота удалить)

1 голос
/ 15 февраля 2009

Попробуйте удалить вызовы Session.refresh (). Из документов:

Перечитайте состояние данного Экземпляр из базовой базы данных. Нецелесообразно использовать это для реализовать длительные сеансы, которые охватывают многие бизнес-задачи. Этот метод Однако полезно в некоторых специальных обстоятельства. Например

  • , где триггер базы данных изменяет состояние объекта при вставке или обновлении
  • после выполнения прямого SQL (например, массового обновления) в том же сеансе
  • после вставки BLOB-объекта или Clob

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

Если вы вызываете flush () перед refresh (), это тоже может решить проблему, поскольку flush () гарантирует, что любой ожидающий SQL будет выполнен для БД. На практике я почти никогда не видел, чтобы кто-нибудь использовал refresh (), и из вашего кода не похоже, что он вам нужен.

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

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

0 голосов
/ 15 февраля 2009

В суперклассе вы отметили поле «содержимое» как временное. Я бы хотя бы подозревал, что это вызывает проблемы. С отображением в подклассе у вас теперь есть два противоречивых отображения для одного и того же атрибута.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...