2013-08-01 19 views
42

Mam do czynienia z problemem, że jeden do jednego leniwy ładowanie nie działa w hibernacji. Mam już rozwiązany , ale nadal nie prawidłowo zrozumieć co się stanie.Hibernate: jeden do jednego leniwy ładowanie, opcjonalnie = fałsz

Mój kod (leniwy załadunku nie działa tutaj, kiedy pociągnąć Person - Adres jest naciągane):

@Entity 
public class Person{ 

    @Id 
    @SequenceGenerator(name = "person_sequence", sequenceName = "sq_person") 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence") 
    @Column(name = "id") 
    private long personID; 

    @OneToOne(mappedBy="person", cascade=CascadeType.ALL, fetch = FetchType.LAZY) 
    private Adress address; 
    //.. getters, setters 
} 

@Entity 
public class Address { 

    @Id 
    @Column(name="id", unique=true, nullable=false) 
    @GeneratedValue(generator="gen") 
    @GenericGenerator(name="gen", strategy="foreign", [email protected](name="property", value="person")) 
    private long personID; 

    @PrimaryKeyJoinColumn 
    @OneToOne 
    private FileInfo person; 
} 

Ale: jeśli dodam optional=false w relacji OneToOne, leniwy ładowanie działa dobrze!

@OneToOne(mappedBy="person", cascade=CascadeType.ALL, optional = false, fetch = FetchType.LAZY) 
private Adress address; 

Pytanie/Entreaty: proszę mi wyjaśnić jak optional=false adnotacja pomaga osiągnąć leniwy załadunku.

P.S. Czytałem posty post1 i post2 i rozumiem, dlaczego prosty OneToOne nie może być leniwy, ale nadal nie mogę uchwycić magii optional=false.

+0

Hej, Wołodymyr, mam z tobą ten sam problem. Próbuję oddzielić kolumnę BLOB od jednostki. Jednostka nadrzędna ma obiekt podrzędny. Element potomny zawiera kolumnę binarną. Rodzic i dziecko to "ten sam stół", więc używam relacji @OneToOne. Chociaż użyłem LAZY fetchType, ale wygląda na to, że nie działa. Kiedy wstawiam 'opcjonalny = fałsz', to działa. Wszelkie wyjaśnienia zostaną docenione naprawdę. – Emerald214

+0

@ Emerald214 Przepraszam, to było 2 lata temu.Obecnie piszę JS Mobile i nie mogę ci pomóc –

+0

OneToOne opcjonalne = false nie działa z CascadeType.PERSIST zobacz: https://hibernate.atlassian.net/browse/HHH-9670 – sliver

Odpowiedz

62

Jeśli powiązanie jest opcjonalne, Hibernate nie ma możliwości sprawdzenia, czy dany adres istnieje dla danej osoby bez wysyłania zapytania. Nie może wypełnić pola adresu proxy, ponieważ nie może być adresów adresowanych do osoby i nie może wypełnić jej wartością null, ponieważ może istnieć adres odnoszący się do osoby.

Po dokonaniu powiązania obligatoryjnego (tj. optional=false), on ci ufa i zakłada, że ​​istnieje adres, ponieważ powiązanie jest obowiązkowe. Więc bezpośrednio wypełnia pole adresu proxy, wiedząc, że istnieje adres odnoszący się do osoby.

+0

opcjonalnie = false nie działa, jeśli próbujesz zapisać Personne bez adresu Adresse: "org.hibernate.PropertyValueException: not-null właściwość odwołuje się do wartości pustej lub przejściowej:" –

+3

optional = false oznacza, że ​​... adres nie jest opcjonalny. Więc jest to obowiązkowe. Zatem ustawienie wartości null powoduje wyjątek. To całkiem spodziewane. –

+0

Tak więc OneToOne, leniwy ładunek, ze wspólnym kluczem podstawowym i opcjonalnym z jednej strony, jest po prostu niemożliwe z hibernacją, prawda? –

5

Najprostszym jest sfałszowanie relacji jeden-do-wielu. To zadziała, ponieważ leniwy ładowanie kolekcji jest znacznie łatwiejsze niż leniwy ładowanie pojedynczej wartości zerowej, ale ogólnie to rozwiązanie jest bardzo niewygodne, jeśli używasz złożonych kwerend JPQL/HQL.

Drugi to użycie oprzyrządowania bajtowego czasu kompilacji. Aby uzyskać więcej informacji, przeczytaj dokumentację Hibernate: 19.1.7. Używanie leniwego pobierania właściwości. Pamiętaj, że w tym przypadku musisz dodać adnotację @LazyToOne(LazyToOneOption.NO_PROXY) do relacji jeden-do-jednego, aby była leniwą. Ustawienie pobierania na LAZY nie wystarczy.

Ostatnim rozwiązaniem jest użycie oprzyrządowania bytecode w czasie pracy, ale będzie działać tylko dla tych, którzy używają Hibernate jako dostawcy JPA w pełnowymiarowym środowisku JEE (w takim przypadku ustawienie "hibernate.ejb.use_class_enhancer" na true powinno załatwić sprawę: Konfiguracja Entity Manager) lub użyj Hibernate with Spring skonfigurowanego do runtime weaving (może to być trudne do osiągnięcia na niektórych starszych serwerach aplikacji). W takim przypadku wymagana jest również adnotacja @LazyToOne(LazyToOneOption.NO_PROXY).