Próbuję użyć obiektu osieroconego w obiektach Hibernuj 4.3.5/JPA2, ale wygląda na to, że nie działa zgodnie z oczekiwaniami. Nie jestem jednak pewien, czy robię coś niepoprawnego, czy też nadal jest to błąd w Hibernate.JPA 2/Hibernate usunięcie sieroty nadal nie działa z @OneToMany?
Biorąc pod uwagę następujące zależności (@version, pobierające i ustawiające pominięty dla zwięzłość):
@Entity
public class Provider implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
private String name;
@OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE)
@JoinColumn(name="provider_id", referencedColumnName="id")
private List<Contract> contracts;
}
@Entity
public class Contract implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
private String volume;
@OneToMany(orphanRemoval=true,cascade=CascadeType.REMOVE) // delete any attachments that were previously uploaded with this contract
@JoinTable(name="contract_attachment", joinColumns = @JoinColumn(name = "contract_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "attachment_id", referencedColumnName = "id"))
private List<Attachment> attachments;
}
@Entity
public class Attachment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
private String filename;
}
Spodziewam się, że jeśli usunąć umowę z listy Provider.contracts, że będzie usunąć odpowiednie wiersze z tabela kontraktów i wszystkie powiązane załączniki z tabeli załączników. Jednak tylko tabela umowy zostanie usunięta. Tabela załączników nie jest modyfikowana.
Ex:
// loop over all contracts and delete the one with the matching id
for(Iterator<Contract> it = provider.getContracts().iterator(); it.hasNext();){
Contract c = it.next();
if(c.getId() == contractId){
it.remove();
break;
}
}
Zważywszy, że załączniki są ManyToOne stosunku do tabeli zamówienia, jeżeli umowa została usunięta, wówczas załączniki są sierotami. Ale nawet z orphanRemoval=true
nie usuwa to wierszy z DB.
Znalazłem kilka problemów związanych z tym dla Hibernate 3 (zarówno tutaj na SO, i Jira i gdzie indziej w Internecie), ale zrozumiałem, że został naprawiony w Hibernate 4. Ale używając Hibernate 4.3.5 nadal widzę to kwestia. Od this issue, wydaje się, że działa, więc nie jestem pewien, dlaczego nie mogę go uzyskać funkcjonalny.
Czy coś jest nie tak/brakuje w moim kodzie lub czy problem z Hibernowaniem jest nadal problematyczny? Czy wymagana jest implementacja equals
i hashCode
w którejkolwiek z tych klas jednostek, aby orphanRemoval
działał poprawnie? Próbowałem implementować obie metody w Kontrakcie i Załączniku, ale nie zrobiłem żadnej różnicy.
Patrząc na logi Hibernacji, pokazuje Hibernate dokonując zmian w tabeli łączenia (lub odwzorowaniu FK), ale tak naprawdę nie usuwa wiersza z powiązanej tabeli. Widzę ustawienie Hibernuj ustawienie provider_id = null w tabeli kontraktu, ale czy nie powinno to usuwać wiersz zamówienia?
2014-07-04 15:06:41,333 [main] [-] DEBUG org.hibernate.SQL -
/* update
com.ia.domain.Provider */ update
provider
set
default_contact_id=?,
name=?,
type=?,
version=?,
website=?
where
id=?
and version=?
Hibernate:
/* update
com.ia.domain.Provider */ update
provider
set
default_contact_id=?,
name=?,
type=?,
version=?,
website=?
where
id=?
and version=?
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [null]
2014-07-04 15:06:41,334 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [2] as [VARCHAR] - [name_3]
2014-07-04 15:06:41,335 [main] [-] TRACE org.hibernate.type.EnumType - Binding [CARRIER] to parameter: [3]
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [4] as [INTEGER] - [2]
2014-07-04 15:06:41,336 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [5] as [VARCHAR] - [website_3]
2014-07-04 15:06:41,337 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [6] as [BIGINT] - [4]
2014-07-04 15:06:41,338 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [7] as [INTEGER] - [1]
2014-07-04 15:06:41,342 [main] [-] DEBUG org.hibernate.SQL -
/* delete one-to-many com.ia.domain.Provider.contracts */ update
contract
set
provider_id=null
where
provider_id=?
Hibernate:
/* delete one-to-many com.ia.domain.Provider.contracts */ update
contract
set
provider_id=null
where
provider_id=?
2014-07-04 15:06:41,344 [main] [-] TRACE hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [4]
Próbowałem aktualizacji podmiotu z 'CascadeType.ALL', ale nadal nie działa. –
@EricB. Czy ustawiłeś '@OneToMany (orphanRemoval = true, cascade = CascadeType.ALL)' na listach 'List; '? Tutaj, z Hibernate 4.3.5.Final i jpa-api-2.1 działa dobrze. Usuwa elementy 'contract_attachment',' Attachment' oraz 'Contract' z DB. –
Zrobiłem pełny czysty, i rzeczywiście, 'CascadeType.ALL' lub' CascadeType.PERSIST' wydaje się działać. Jednak problem polega na tym, że nie chcę wykonywać 'CascadeType.PERSIST'! Czy 'orphanRemoval' nie powinien być niezależny od kaskady? –