Спящий режим, удаляющий сирот при обновлении коллекции
Я нахожу, что сиротские записи не удаляются при удалении из коллекции в 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.
Любые советы будут очень признательны!
EDIT: Спасибо за все отзывы. В дополнение к комментариям ниже, я добавил @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
к родительскому, так что теперь:
public class Author
{
@OneToMany(cascade={CascadeType.ALL})
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
List<Book> books;
}
Я все еще нахожу те же результаты. Я ДОЛЖЕН пропустить что-то простое.
Ответы
Ответ 1
Ты не делаешь ничего плохого. Вы просто не удаляете дочерний объект. Вы можете сделать это с помощью явного remove() дочернего объекта (в дополнение к тому, что вы делаете) или использовать эту аннотацию, которая приведет к удалению записей сирот.
Кроме того, стоит упомянуть, что CascadeType.DELETE
также не будет удалять сирот. Это значит что-то еще. См. JPA CascadeType.ALL не удаляет сирот.
В основном, чтобы сделать это автоматически, вы захотите этого в коллекции в родительском объекте:
org.hibernate.annotations.CascadeType.DELETE_ORPHAN
Ответ 2
для людей, которые ищут свое решение: теперь в Hibernate, соотв. JPA 2.0, это правильный путь:
@OneToMany(orphanRemoval=true)
Ответ 3
Параметр каскада в аннотации @OneToMany
представляет собой массив, который вы хотите:
@OneToMany(cascade={CascadeType.ALL, CascadeType.DELETE_ORPHAN})
Ответ 4
Попробуйте использовать следующую аннотацию, если вы хотите "переходную зависимость".
@org.hibernate.annotations.Cascade(CascadeType.DELETE_ORPHAN)
Ответ 5
добавьте @onDelete, возможно, эта работа для вас
public class Author
{
@OneToMany(cascade={CascadeType.ALL})
@OnDelete(action = OnDeleteAction.CASCADE)
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
List<Book> books;
}
Ответ 6
Похоже, вам не хватает аннотации mappedBy. Попробуйте:
public class Book {
@ManyToOne
@NotNull
Author author;
}
public class Author {
@OneToMany(mappedBy="author", cascade={CascadeType.ALL})
List<Book> books;
}
Ответ 7
Я знаю, что опаздываю на вечеринку, и я понимаю, что уже много было сказано по этой теме, но ИМХО, я бы не использовал delete-orphans в качестве каскадного варианта. Я предпочел бы удалить дочерние ассоциации вручную перед удалением родителя. Один небольшой недосмотр... и длинная цепочка ассоциаций может быть удалена за секунду. Да! Я согласен, что это может быть именно то, что хотелось бы при некоторых обстоятельствах.