2010-08-22 5 views
5

Mam encję, która zawiera dwie inne jednostki o relacji @ManyToOne.Hibernate i NonUniqueObjectException

@Entity 
public class A extends Serializable{ 

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

    @ManyToOne 
    @Cascade(CascadeType.SAVE_UPDATE) 
    private B b; 

    @ManyToOne 
    @Cascade(CascadeType.SAVE_UPDATE) 
    private C c; 

} 

Jeśli próbuję zapisać Instancja że mają "B_ID" i "C_ID" innego rekordu A i uzyskać wyjątek:

org.hibernate.NonUniqueObjectException: inny obiekt z tego samego wartość identyfikator został już powiązany z sesji

na przykład:

A table 
| ID | B_ID | C_ID | 
| 1 |  1 | null | // this works 
| 2 | null |  1 | // this works 
| 3 |  1 |  x | // this throws the exception 
| 4 |  x |  1 | // this throws the exception 

x=any value of existent B/C_ID 

B_ID i C_ID nie są unikalne w moim modelu i (B_ID + C_ID) nie są wyjątkowym ograniczeniem !!

Co mogę zrobić?

Z góry dziękuję.

Odpowiedz

15

Hibernate nie narzeka tu na wyjątkowość bazy danych, narzeka, że ​​obecny numer Session zawiera już obiekt o tym samym identyfikatorze co nowy obiekt, który próbujesz zapisać. Nie pozwoli na to - Hibernate ma ścisły wymóg, aby dany identyfikator nie mógł być reprezentowany przez dwa różne obiekty w zakresie pojedynczej sesji.

W pewnym momencie aplikacja zapisuje dor załadowany obiekt o tym samym ID, a obiekt jest już "zarejestrowany" w sesji. Trudno powiedzieć w tym konkretnym przypadku, który identyfikator narzeka, ponieważ tekst wyjątku nie jest jasny. Spróbuj tymczasowo usunąć dyrektywy kaskadowe i sprawdź, czy nadal się zdarza, spróbuj go zawęzić.

W razie potrzeby można zmusić sesję do "zapomnienia" o istniejących obiektach dla danego ID (przy użyciu Session.evict() w interfejsie API Hibernate lub EntityManager.detach() w interfejsie API JPA 2.0), ale to nie jest bardzo eleganckie rozwiązanie.

Powtórzmy - ten wyjątek nie ma nic wspólnego z ograniczeniami bazy danych, dotyczy hibernacji, która chroni spójność wewnętrznego stanu w pamięci.

+0

Dzięki, jedyne rzeczy, które ładuję z db to B i C, i używam ich w obiekcie A. Ale B i C mają CascadeType.SAVE_UPDATE, więc nie są zapisywane ponownie, ale tylko aktualizacja ... mam nadzieję ... – blow

+0

Problemy pojawiają się również na początku, gdy sesja jest nowa. – blow

+0

usuwanie dyrektyw kaskadowych działa dobrze, ale ... DLACZEGO ??? Bez "Cascade.SAVE_UPDATE" hibernacja powinna próbować ponownie ZAPISZ "A" i "B", które są już prezentowane w db, a więc wyrzucić wyjątek, ale działa zamiast ... dlaczego? – blow