2013-08-17 7 views
6

używam Wiosna 3.2.3 i 4.2.3 i JDK hibernacji 7.obiekt odwołuje niezapisaną przemijające wystąpienie: jak opróżnić lub powrót zapisany obiekt

Mam proste podmiot:

@Entity 
public class Language { 
    @Id 
    @GeneratedValue 
    private long id; 

    @Column(nullable = false, length = 3, unique = true) 
    private String code; 
} 

I zapisany wystąpienie tego podmiotu za pomocą @Service uwagami klasę z @Transactional opatrzony metody wykorzystującej DAO, która zapisuje podmiotowi

sessionFactory.getCurrentSession().save(object); 

Następnie użyć D zapisaneLanguage podmiotu do tworzenia EntityX, który wykorzystywał ją w stosunku ManyToOne ...

lang=new Language(); 
// ... 
languageService.saveLanguage(lang); 
e=new EntityX(); 
// ... 
e.setLanguage(lang); 
otherService.saveEntity(e); 

i EntityX jest zdefiniowany jako ...

@Entity 
public class EntityX { 
    @ManyToOne 
    @JoinColumn(nullable = false) 
    private Language language; 
     // ... 
} 

zawsze dotrzesz wyjątek

Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: somepackage.Language 

Próbuję użyć niektórych definicji kaskadowych w EntityX " s stosunek do Language jak sugerowano w innych postach, ale nie ma żadnego efektu.

Jeśli ponownie załaduję zapisany obiekt Language, znajdując go za pomocą jego zapytania code przy użyciu kwerendy HQL, wszystko działa poprawnie, ale jest ono dalekie od bycia "miłym".

Niestety metoda (y) save(...) z org.hibernate.Session nie zwraca zapisanego obiektu.

Czy ktoś ma pomysły, jak go rozwiązać?

Odpowiedz

5

to ty kod w jednej metody @Transactional?
Jeśli nie, problem może polegać na tym, że po każdej metodzie wywołania usługi transakcja zostanie zatwierdzona i sesja wyczyszczona. Podczas próby zapisania obiektu obiekt języka nie jest wykrywany w sesji i zarządzany jako instancja tymczasowa i podaje błąd.

W przypadku, gdy kod jest w ramach pojedynczej transakcji nie spróbować flush() przed zapisaniem podmiot zmusić sklep hibernacji Language do bazy danych i przypisać mu poprawny @Id entifier?

Po wszystkim - IMHO - jeśli masz zależności od podmiotu i Języka najlepszym wyborem jest:

@ManyToOne(cascade = CascadeType.ALL) 
private Language language; 

i zmienić swój kod jako:

e=new EntityX(); 
Language lang = new Language(); 
// ... 
e.setLanguage(lang); 
otherService.saveEntity(e); 

i nie trzeba do obiekt trwały w dwóch etapach (język + encja); zarządzaj językiem + jednostką jako pojedynczą pozycją

PS: Metoda zapisu (...) org.hibernate.Session nie zwraca zapisanego obiektu, ponieważ obiekt pozostanie taki sam (odniesienie nie zmień), zmieniają się tylko właściwości obiektu (na przykład ten oznaczony jako @Id)!

EDYTOWANIE:
Stwórz obiekt trwały (mam na myśli Session.save()) nie powoduj natychmiastowego wstawiania/aktualizacji; bez wskazówki kaskady Wygląd hibernacji nie wykrywa zależności między EntityX i Language i nie wykonuje wstawienia sql języka przed zapisaniem EntityX.
Wywołanie languageService.save (język) nie wykonuje session.flush(), ponieważ użytkownik jest pod tym samym @Transactional i bez session.commit() nie jest wykonywany session.flush() i najlepszą opcją jest to, że obiekt Language jest nadal oznaczony jako przejściowy.
Możesz wykonać sprawdzenie: wyodrębnij usługi, zapisz kod (język encjiX) i wstaw wszystko pojedynczo @Transactional i sprawdź, czy Hibernacja nadal daje błąd.
Moja najlepsza opcja nadal wykonuje spłukiwanie() w środku lub zmieniaj mapowanie, nie ma innej drogi.

+0

Kod znajduje się w pojedynczej metodzie '@ Transactional'. Metody usług są również "@ Transactional", ale nie wymagają nowej transakcji, więc przypuszczam, że istniejący jest używany. Zapisałem język dla siebie, ponieważ mam jedną jednostkę języka i wiele jednostek EntityX, a każda z nich używa tej samej jednostki języka. – t777

+1

Sprawdź moją edycję, zbyt długo na komentarz. Mam nadzieję, że będzie jasne, angielski nie jest moim ojczystym językiem, przepraszam –

+0

Hi @ LucaBassoRicci, Mam ten sam problem, ale moja technologia jest inna, możesz rzucić okiem na to .. http://stackoverflow.com/questions/28279304/error-when-saving-a-object-który-has-foreign-object-references-references-an-unsaved –

2

Po pierwsze, jeśli pole code jest kluczem podstawowym (lub są przynajmniej używając go jako podstawowy identyfikator dla hibernacji), należy określić @Id:

@Id 
@GeneratedValue(generator="assigned") 
@Column(length = 3) 
private String code; 

Nie określając kolumna ID może być mylące Hibernate trochę; chociaż nie cytuj mnie w tej sprawie.

Jeśli save() nadal nie działa po tym, można użyć merge():

Language lang = new Language("XYZ"); 
lang = session.merge(lange); 
+0

Przykro mi. Zbyt wiele skróciłem swój kod. Jest pole identyfikacyjne. Dodałem go do kodu mojego wpisu. Mam ten sam problem, gdy używam scalania zamiast zapisywania. – t777

Powiązane problemy