Po pierwsze, kilka wyjaśnień do odpowiedzi KLE :
Nieograniczone (zerowalne) skojarzenie jeden do jednego jest jedynym, które nie może być proxy bez oprzyrządowania z kodem bajtowym. Powodem tego jest to, że jednostka właściciela MUSI wiedzieć, czy właściwość asocjacji powinna zawierać obiekt proxy, czy NULL, i nie może tego ustalić, patrząc na kolumny swojej tabeli podstawowej ze względu na normalne odwzorowanie jeden do jednego za pośrednictwem współdzielonego PK, więc i tak musi być chętnie pobierany, przez co proxy nie ma sensu. Oto bardziej szczegółowe wyjaśnienie.
stowarzyszenia wiele do jednego (i oczywiście jeden do wielu) nie cierpią z powodu tego problemu. Podmiot będący właścicielem może łatwo sprawdzić swój FK (aw przypadku „jeden do wielu” początkowo tworzony jest pusty serwer proxy kolekcji i zapełniany na żądanie), więc powiązanie może być leniwe.
Zamiana jeden na jeden na jeden na wielu nigdy nie jest dobrym pomysłem. Możesz go zastąpić unikatowym rozwiązaniem wiele do jednego, ale istnieją inne (być może lepsze) opcje.
Rob H. ma rację, ale możesz nie być w stanie go wdrożyć w zależności od modelu (np. Jeśli twoje powiązanie jeden do jednego jest zerowane).
Jeśli chodzi o oryginalne pytanie:
A) @ManyToOne(fetch=FetchType.LAZY)
powinien działać dobrze. Czy na pewno nie jest zastępowane w samym zapytaniu? Możliwe jest określenie join fetch
w HQL i / lub jawne ustawienie trybu pobierania poprzez Criteria API, który miałby pierwszeństwo przed adnotacjami klas. Jeśli tak nie jest i nadal masz problemy, opublikuj swoje klasy, zapytanie i wynikowy SQL, aby uzyskać bardziej szczegółową rozmowę.
B) @OneToOne
jest trudniejsze. Jeśli zdecydowanie nie ma wartości zerowej, skorzystaj z sugestii Roba H. i określ ją jako taką:
@OneToOne(optional = false, fetch = FetchType.LAZY)
W przeciwnym razie, jeśli możesz zmienić bazę danych (dodaj kolumnę klucza obcego do tabeli właściciela), zrób to i zamapuj ją jako „połączoną”:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()
oraz w OtherEntity:
@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()
Jeśli nie możesz tego zrobić (i nie możesz żyć z chętnym pobieraniem) instrumentacja z kodem bajtowym jest twoją jedyną opcją. Muszę jednak zgodzić się z CPerkins - jeśli masz 80 !!! dołącza z powodu chętnych skojarzeń OneToOne, masz większe problemy niż to :-)
one-to-one
z formułą podobną doselect other_entity.id from other_entity where id = other_entity.id
. Oczywiście nie jest to idealne rozwiązanie do wykonywania zapytań.Aby uzyskać leniwe ładowanie podczas pracy nad zerowalnymi mapowaniami jeden-do-jednego, musisz pozwolić hibernacji skompilować instrumentację czasu i dodać
@LazyToOne(value = LazyToOneOption.NO_PROXY)
relację jeden-do-jednego.Przykładowe mapowanie:
Przykład rozszerzenia pliku Ant Build (do wykonania instrumentacji czasu kompilacji Hibernacja):
źródło
LazyToOneOption.NO_PROXY
nieLazyToOneOption.PROXY
?Podstawową ideą XToOnes w Hibernacji jest to, że w większości przypadków nie są leniwi.
Jednym z powodów jest to, że gdy Hibernacja musi zdecydować się na ustawienie serwera proxy (z identyfikatorem) lub wartości zerowej,
musi i tak spojrzeć na drugą tabelę, aby dołączyć. Koszt dostępu do drugiej tabeli w bazie danych jest znaczny, więc równie dobrze może pobrać dane dla tej tabeli w tym momencie (zachowanie nie leniwe), zamiast pobierać to w późniejszym żądaniu, które wymagałoby drugiego dostępu do ten sam stół.
Edytowane: szczegółowe informacje znajdują się w odpowiedzi ChssPly76 . Ten jest mniej dokładny i szczegółowy, nie ma nic do zaoferowania. Dzięki ChssPly76.
źródło
Oto coś, co działało dla mnie (bez oprzyrządowania):
Zamiast używać
@OneToOne
po obu stronach, używam@OneToMany
w odwrotnej części relacji (tej zmappedBy
). To sprawia, że właściwość jest kolekcją (List
w poniższym przykładzie), ale tłumaczę ją na element w module pobierającym, dzięki czemu jest przezroczysty dla klientów.Ta konfiguracja działa leniwie, to znaczy, że wybiera się tylko gdy wykonane
getPrevious()
lubgetNext()
są nazywane - i tylko jeden wybór dla każdego połączenia.Struktura tabeli:
Klasa:
źródło
Jak wyjaśniłem w tym artykule , chyba że korzystasz z Bytecode Enhancement , nie możesz leniwie pobrać
@OneToOne
powiązania strony nadrzędnej .Jednak najczęściej nie potrzebujesz nawet powiązania strony nadrzędnej, jeśli używasz
@MapsId
po stronie klienta:Z
@MapsId
Theid
nieruchomość w tabeli podrzędnej służy zarówno jako klucz podstawowy i klucz obcy do tabeli nadrzędnej klucz podstawowy.Jeśli więc masz odniesienie do
Post
encji nadrzędnej , możesz łatwo pobrać encję podrzędną za pomocą identyfikatora encji nadrzędnej:W ten sposób nie będziesz mieć problemów z zapytaniami N + 1, które mogą być spowodowane przez
mappedBy
@OneToOne
powiązanie po stronie nadrzędnej.źródło
W natywnych mapowaniach XML Hibernacji można to osiągnąć, deklarując mapowanie jeden do jednego z ograniczonym atrybutem ustawionym na wartość true. Nie jestem pewien, co to jest odpowiednik adnotacji Hibernacja / JPA, a szybkie przeszukanie dokumentu nie dało odpowiedzi, ale mam nadzieję, że da ci to przewagę.
źródło
@OneToOne(optional=false,fetch=FetchMode.LAZY)
Jak już doskonale wyjaśniono w ChssPly76, serwery proxy Hibernacji nie pomagają w nieskrępowanych (zerowalnych) skojarzeniach jeden-do-jednego, ALE jest wyjaśniona tutaj sztuczka , aby uniknąć konfiguracji instrumentacji. Chodzi o to, aby oszukać Hibernację, że klasa encji, której chcemy użyć, została już instrumentowana: instrumentujesz ją ręcznie w kodzie źródłowym. To jest łatwe! Zaimplementowałem go z CGLib jako dostawcą kodu bajtowego i działa (upewnij się, że w HBM skonfigurujesz lazy = "no-proxy" i fetch = "select", a nie "join").
Myślę, że jest to dobra alternatywa dla prawdziwych (tzn. Automatycznych) instrumentów, kiedy masz tylko jeden związek zerowy, który chcesz rozluźnić. Główną wadą jest to, że rozwiązanie zależy od dostawcy kodu bajtowego, którego używasz, więc dokładnie komentuj swoją klasę, ponieważ w przyszłości będziesz musiał zmienić dostawcę kodu bajtowego; oczywiście modyfikujesz również model bean z przyczyn technicznych i to nie jest w porządku.
źródło
To pytanie jest dość stare, ale w Hibernacji 5.1.10 pojawiły się nowe, bardziej wygodne rozwiązania.
Leniwe ładowanie działa z wyjątkiem strony nadrzędnej powiązania @OneToOne. Wynika to z faktu, że Hibernacja nie ma innego sposobu dowiedzenia się, czy przypisać wartość zerową czy proxy do tej zmiennej. Więcej informacji można znaleźć w tym artykule
źródło
Jeśli relacja nie może być dwukierunkowa, wówczas @ElementCollection może być łatwiejsze niż używanie leniwej kolekcji One2Many.
źródło