Hibernate удаление сирот при обновлении коллекции - PullRequest
30 голосов
/ 20 августа 2009

Я обнаружил, что потерянные записи не удаляются при удалении из коллекции в Hibernate. Должно быть, я делаю что-то не так (это Hibernate-101!), Но я не могу найти это ..

Учитывая следующее:

public class Book {
    @ManyToOne
    @NotNull
    Author author;
}
public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    List<Book> books;
}

И следующий код обновления:

Author author = authorDAO.get(1);
Book book = author.getBooks().get(0);
author.getBooks().remove(0);
authorDAO.update(author);

Фрагмент AuthorDAO:

@Override
public void update(T entity) {
    getSession().update(entity);
}

Следующий тест не пройден:

Author author = author.get(1);
assertEquals(0,author.getBooks().size()); // Passes
Book dbBook = bookDAO.get(book.getId())
assertNull(dbBook); // Fail!  dbBook still exists!
assertFalse(author.getBooks().contains(dbBook) // Passes!

В итоге я нахожу:

  • Хотя книга удалена из авторской коллекции книг, она все еще существует в базе данных
  • Если я изучу book.getAuthor().getBooks(), книга не существует в этой коллекции

Такое ощущение, что я не сбрасываю сессию и не запускаю обновление соответствующим образом - но я не уверен, где мне следует это делать. В том же духе, другие моменты, которые могут повлиять:

  • Я выполняю вышеупомянутое в тесте JUnit, украшенном @RunWith(SpringJUnit4ClassRunner.class)
  • Первоначально я столкнулся с этой проблемой в процедуре обновления, которая украшена @Transactional, однако с тех пор я воссоздал ее в простом старом тесте JUnit.

Любой совет будет с благодарностью!

РЕДАКТИРОВАТЬ: Спасибо за все отзывы уже. В дополнение к комментариям ниже, я добавил @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) к родителю, так что теперь это:

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}

Я все еще нахожу те же результаты. Я ДОЛЖЕН пропустить что-то простое.

Ответы [ 6 ]

41 голосов
/ 12 декабря 2012

для людей, которые ищут свое решение: теперь в Hibernate, соотв. JPA 2.0, это правильный путь:

@OneToMany(orphanRemoval=true)
19 голосов
/ 20 августа 2009

Вы не делаете ничего плохого. Вы просто не удаляете дочернюю сущность. Вы можете сделать это с помощью явного удаления () дочерней сущности (в дополнение к тому, что вы делаете) или использовать эту аннотацию, которая приводит к удалению потерянных записей.

Также стоит отметить, что CascadeType.DELETE также не удалит сирот. Это означает что-то еще. См. JPA CascadeType.ALL не удаляет сирот.

В основном, чтобы сделать это автоматически, вы захотите это для коллекции в родительском элементе:

org.hibernate.annotations.CascadeType.DELETE_ORPHAN
3 голосов
/ 20 августа 2009

Каскадная опция в аннотации @OneToMany - это массив, который вам нужен:

@OneToMany(cascade={CascadeType.ALL, CascadeType.DELETE_ORPHAN})
0 голосов
/ 21 августа 2009

Похоже, вам не хватает аннотации mappedBy . Попробуйте:

public class Book {
  @ManyToOne
  @NotNull
  Author author;
}
public class Author {
  @OneToMany(mappedBy="author", cascade={CascadeType.ALL})
  List<Book> books;
}
0 голосов
/ 20 августа 2009

пожалуйста, добавьте @onDelete, может быть, эта работа для вас

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @OnDelete(action = OnDeleteAction.CASCADE)
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}
0 голосов
/ 20 августа 2009

Попробуйте использовать следующую аннотацию, если вы хотите поведение «транзитивной зависимости».

@org.hibernate.annotations.Cascade (CascadeType.DELETE_ORPHAN)

...