Mam dwie fasoli podmiot określone następująco (niezwiązany materiał usunięto):Zatrzymaj Hibernate z aktualizacją kolekcji, gdy nie zostały zmienione
@Entity
@Table(...)
public class MasterItem implements java.io.Serializable {
private Set<CriticalItems> criticalItemses = new HashSet<CriticalItems>(0);
@OneToMany(fetch = FetchType.EAGER, mappedBy = "masterItem", orphanRemoval = true,
cascade = {javax.persistence.CascadeType.DETACH})
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
public Set<CriticalItems> getCriticalItemses() {
return this.criticalItemses;
}
}
CriticalItems jest zdefiniowany następująco:
@Entity
@Table(...)
public class CriticalItems implements java.io.Serializable {
private MasterItem masterItem;
@ManyToOne(fetch = FetchType.LAZY, optional = false,
cascade = {javax.persistence.CascadeType.DETACH})
@Cascade({CascadeType.SAVE_UPDATE})
@JoinColumn(name = "mi_item_id", nullable = false)
public MasterItem getMasterItem() {
return this.masterItem;
}
}
i moim Kod DAO - Mam następujące metody:
public MasterItem load(int id) {
MasterItem results = (MasterItem) getSessionFactory().getCurrentSession()
.get("com.xxx.MasterItem", id);
}
public void save(MasterItem master) {
// master has been changed by the UI since it
getSessionFactory().getCurrentSession().saveOrUpdate(master);
}
Po załadowaniu MasterItem, ładuje się poprawnie, d również ładuje zestaw CriticalItems z danymi, zgodnie z poleceniami. Następnie wysyłam te dane do mojego interfejsu użytkownika i otrzymuję zaktualizowaną kopię, którą następnie próbuję kontynuować. Użytkownik aktualizuje pola w obiekcie MasterItem, ale nie dotyka Zestawu Elementów Krytycznych ani niczego w nim zawartego - pozostaje niezmieniony.
Kiedy wywoływana jest moja metoda save(), Hibernate nalega na wysyłanie aktualizacji SQL dla każdego elementu w Zestawie Elementów Krytycznych, nawet jeśli żadna z nich w żaden sposób się nie zmieniła.
Po pewnym kopaniu, oto co myślę dzieje się. Kiedy robię saveOrUpdate(), Hibernate widzi mój obiekt MasterItem jest w stanie odłączonym, więc próbuje przeładować go z dysku. Jednak w takim przypadku wydaje się, że używa on przygotowanej instrukcji (która została automatycznie utworzona przez Hibernate przy uruchomieniu), a ta przygotowana instrukcja nie próbuje dołączyć do danych CriticalItems.
Tak Hibernacja ma mój zaktualizowany obiekt MasterItem z pełnym zestawem elementów CriticalItems, ale używa MasterItem bez kolekcji jako obiektu "previousState". W ten sposób wszystkie krytyczne itemy są aktualizowane za pomocą SQL (nie włożone, co jest interesujące samo w sobie).
Czy zrobiłem coś w moich adnotacjach, które spowodowały takie zachowanie? Wiem, że mogę użyć Interceptora, aby dowiedzieć się, czy element naprawdę się zmienił, lub zmienić brudną flagę, aby zastąpić domyślny algorytm Hibernate - ale wydaje się, że to coś, co Hibernate powinien sam poradzić sobie bez mojej interwencji.
Każdy wgląd byłby doceniony.
UPDATE: podstawie wypowiedzi, myślę, że zrozumieć różnicę między saveOrUpdate() i scalić(). Zdaję sobie sprawę, że saveOrUpdate() spowoduje albo SQL INSERT lub SQL UPDATE we wszystkich przypadkach, i że scalenie, w teorii, wyda tylko aktualizacje, jeśli obiekt zmienił się z trwałego stanu, ale w celu ustalenia tego, Hibernate musi najpierw przeładować obiekt przez SQL SELECT.
Tak, myślałem, że mógłbym tylko wrócić do mojego kodu i zmienić saveOrUpdate(), aby scalić() i to by działało, ale to nie było tak.
Kiedy użyłem seryjnej(), byłem coraz
org.springframework.orm.hibernate3.HibernateSystemException: could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session
ale to działało w porządku, gdybym zmienił z powrotem do saveOrUpdate().
W końcu dowiedziałem się, dlaczego - nie zawierałem CascadeType.MERGE
w mojej adnotacji @Cascade
(ugh). Kiedy to naprawiłem, wyjątek odszedł.
czy masz optymistyczną kolumnę blokującą (kolumna z adnotacją @version z typem albo datą int) – lweller