Каскадно изтриване на колекция от обекти за вграждане

Имам обект A, който има колекция от основни типове (напр. String). Използвам такова съпоставяне, защото низовете, свързани с всеки екземпляр на A, зависят от жизнения цикъл на A. Ако искам да премахна екземпляр на A от DB, искам също да премахна свързаните с него Strings.

Моето картографиране е както следва:

@Entity
public class A {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name", nullable = false, unique = true)
    private String name;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "AStrings", joinColumns = @JoinColumn(name = "id"))
    @Column(name = "strings", nullable = false)
    private Set<String> strings;
}

Ако създам екземпляр на A и му добавя някои низове, тогава мога да запазя екземпляра с помощта на Session.save(myInstance). Както екземплярът на A, така и свързаните с него Strings се запазват.

Но ако искам да премахна същия екземпляр от DB, използвайки Session.createQuery("delete A a where a.name = ?").setString(0, name).executeUpdate(), получавам грешка при ограничение на външен ключ:

Не може да се изтрие или актуализира родителски ред: ограничение за външен ключ е неуспешно

Но бих очаквал свързаните Strings да бъдат премахнати автоматично, преди да премахнете екземпляра на A, но изглежда, че не е така. Също така не намерих начин да задам каскадни правила.

Има ли нещо нередно с конфигурацията ми?

Благодаря


РЕДАКТИРАНЕ: Опитах също да използвам @Cascade(CascadeType.DELETE) на поле strings и пак не помага. Разглеждайки базата данни, не виждам никаква ON DELETE политика за съответния външен ключ.

Някой, който е имал същия проблем, отвори JIRA: https://hibernate.onjira.com/browse/HHH-4301. Трябва да съществува решение (или заобиколно решение), не мога да бъда единственият човек, който използва @ElementCollection.

Реших проблема. Мислех, че изтриването чрез Session.delete() или използването на HQL заявка е еквивалентно, но изглежда не е така. Използвайки HQL заявка, зависимите обекти не се изтриват автоматично, така че получавам грешка при ограничение на външен ключ. Използването на Session.delete() решава проблема. Освен това изглежда, че Hibernate не използва каскадна функционалност на DB, тъй като все още не виждам никаква CASCADE политика в генерирания DDL, той обработва това вътрешно.


person Mickael Marrache    schedule 29.08.2012    source източник


Отговори (4)


Реших проблема.

Мислех, че изтриването на обект с помощта на Session.delete() или с помощта на HQL заявка е еквивалентно, но изглежда не е така. Използвайки HQL заявка, зависимите обекти не се изтриват автоматично, така че получавам грешка при ограничение на външен ключ, както е обяснено във въпроса.

Използването на Session.delete() решава проблема. Освен това изглежда, че Hibernate не използва каскадна функционалност на DB, тъй като все още не виждам никаква CASCADE политика в генерирания DDL, той обработва това вътрешно.


За модератори:

Добавих отговора си към въпроса в миналото (както попитахте), но тъй като това е отговорът, който решава проблема и не е публикуван отговор (от други потребители), мисля, че трябва да го публикувам тук като отговор .

person Mickael Marrache    schedule 15.01.2013
comment
Това наистина работи! Проблемът е, че е много по-бавно използването на HQL... - person BrunoJCM; 17.11.2016

  • какво ще кажете за добавяне на orphanRemoval конфигурация?

  • или да извикате A.strings().clear() ръчно, преди да изтриете един A екземпляр?

ако и двете по-горе не работят, може би има някакъв бъг за ElementCollection

person donnior    schedule 29.08.2012

Тествайте принудително изтриване на осиротяло:

@Cascade( { org.hibernate.annotations.CascadeType.ALL, 
    org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
person Manu Navarro    schedule 29.08.2012
comment
@Cascade е за обекти @OneToManys, а не за @ElementCollections. - person BrunoJCM; 16.11.2016

Добавяне на „@Cascade“ (org.hibernate.annotations.Cascade)

Ex:

@Entity
public class A {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "AStrings", joinColumns = @JoinColumn(name = "id"))
    @Column(name = "strings", nullable = false)
    @Cascade(value=org.hibernate.annotations.CascadeType.ALL)
    private Set<String> strings;
}
person Manu Navarro    schedule 29.08.2012
comment
@Cascade е за обекти @OneToManys, а не за @ElementCollections. - person BrunoJCM; 16.11.2016