Может кто-нибудь объяснить orphanRemoval в Hibernate?

Мой вопрос не в том, как работает «mappedBy». Я знаю, просто указывает на владельца отношения. Мой вопрос в том, как работает orphanRemoval. А в моем случае я вообще не использую индикацию mappedBy.

У меня есть следующие сущности:

@Entity
@Table(name = "catalog_orphan")
public class CatalogOrphan extends AbstractBaseEntity<Long> {

    @OneToMany(orphanRemoval = true)
    private List<GoodOrphan> goodOrphans;

    public List<GoodOrphan> getGoodOrphans() {
        return goodOrphans;
    }

    public void setGoodOrphans(List<GoodOrphan> goodOrphans) {
        this.goodOrphans = goodOrphans;
    }
}

@Entity
@Table(name = "good_orphan")
public class GoodOrphan extends AbstractBaseEntity<Long> {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "catalog_orphan_id")
    private CatalogOrphan catalogOrphan;

    public CatalogOrphan getCatalogOrphan() {
        return catalogOrphan;
    }

    public void setCatalogOrphan(CatalogOrphan catalogOrphan) {
        this.catalogOrphan = catalogOrphan;
    }
}

@MappedSuperclass
public abstract class AbstractBaseEntity<ID> {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected ID id;

    @Column(name = "name")
    protected String name;
}

А я пытаюсь протестировать функционал удаления сирот.

И я написал следующий тест:

@RunWith(SpringRunner.class)
@DataJpaTest
@TestExecutionListeners({
        TransactionalTestExecutionListener.class,
        DependencyInjectionTestExecutionListener.class,
        DbUnitTestExecutionListener.class
})
@DatabaseSetup("/persistCascade/orphan/catalog_good_orphan.xml")
public class CatalogOrphanTest {

    @Autowired
    protected TestEntityManager entityManager;

    @Test
    public void clearCollections() {
        CatalogOrphan catalog = entityManager.find(CatalogOrphan.class, 1L);

        catalog.getGoodOrphans().clear();
        entityManager.persist(catalog);

        entityManager.flush();
        entityManager.clear();

        CatalogOrphan catalogAfterCleanCollection2 = entityManager.find(CatalogOrphan.class, 1L);
        assertThat(catalogAfterCleanCollection2.getGoodOrphans().size(), equalTo(0)); // Does this mean that the connection has been deleted?

        GoodOrphan goodOrphan = entityManager.find(GoodOrphan.class, 1L);
        assertThat(goodOrphan.getCatalogOrphan(), is(notNullValue()));  // WHY???
    }
}

catalog_good_orphan.xml:

<dataset>
    <Catalog_Orphan id = "1" name = "Catalog#1"/>
    <Catalog_Orphan id = "2" name = "Catalog#2"/>

    <Good_Orphan id = "1" name = "Good#1" catalog_orphan_id = "1"/>
    <Good_Orphan id = "2" name = "Good#2" catalog_orphan_id = "1"/>
    <Good_Orphan id = "3" name = "Good#3" catalog_orphan_id = "2"/>
    <Good_Orphan id = "4" name = "Good#4" catalog_orphan_id = "2"/>

    <!-- without catalog -->
    <Good_Orphan id = "5" name = "Good#5" />
</dataset>

Я вообще не понимаю смысла "orphanRemoval = true". Почему он так работает? В результате мы убираем только ссылку на "GoodOrphan" из "CatalogOrphan", а ссылка с "GoodOrphan" на "CatalogOrphan" остается.

Что я делаю неправильно? или это правильное поведение?

Возможный дубликат Может кто-нибудь объяснить mappedBy в спящем режиме?

crizzis 08.04.2019 22:26

@crizzis спасибо за комментарий. Но нет, на мой вопрос нет ответа.

FreeOnGoo 09.04.2019 08:47
Что я делаю неправильно?: вы не используете mappedBy. Таким образом, вместо двунаправленных ассоциаций у вас есть две отдельные независимые ассоциации: OneToMany (с использованием объединенной таблицы) и ManyToOne (с использованием столбца соединения). Вот как вы определяете двунаправленную ассоциацию OneToMany: docs.jboss.org/hibernate/orm/current/userguide/html_single/…
JB Nizet 09.04.2019 09:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
108
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

removeOrphan удаляет элемент из базы данных, когда он больше не связан с родителем. Это работает только тогда, когда вы удаляете элемент из списка в том же сеансе. Примечание: удаление из списка и удаление ссылки из элемента на родителя — это две разные вещи, хотя вы (должны) использовать один и тот же внешний ключ в базе данных для этих двух ссылок.

Примечание. Это не работает, когда вы удаляете элемент из одного списка и добавляете его в другой. Когда вам повезет, вы получите исключение, которое говорит вам, что это не работает.

Другие вопросы по теме

Похожие вопросы

Получить объект из коллекции
Каждая версия Java поставляется как в 32-битной, так и в 64-битной версии?
HibernateException: не удалось определить тип исключения класса с помощью собственного запроса spring-data-jpa для postgresql
Регулярное выражение для любого числа или значения NULL
Выполнять функцию Dart в фоновом режиме, когда автозапуск приложения флаттера находится в состоянии BOOT_COMPLETED?
Не удалось подключиться к образу докера с помощью весеннего загрузочного приложения
Как обеспечить, чтобы все данные, принадлежащие пользователю, попадали в один и тот же файл при использовании spark?
Как я могу проверить и отобразить слово между двумя другими конкретными словами?
Является ли создание атрибута без использования наследования правильным дизайном? Вызывает проблемы в сериализации. Джава
Swing Timer не запускается в графическом интерфейсе Java *ОБНОВЛЕНО