2012-04-15 20 views
6

Mam tu do czynienia z przegraną i być może jest to coś oczywistego, ponieważ moja wiedza na temat Hibernacji jest słabsza niż w innych dziedzinach.Hibernuj zamień klasę embeddable na migrację istniejących danych

W starszym kodzie występuje klasa Hibernate @Entity klasa Foo. Jedną z jego właściwości to:

private OldBar bar = new OldBar(); 

OldBar jest klasa @Embeddable który wykorzystuje pojedynczą kolumnę, foobar:

@Embeddable 
public class OldBar { 

    private String fooBar; 

    @Column(length = 10, nullable = false) 
    private String getFooBar() { 
    return fooBar; 
    } 

    @SuppressWarnings("unused") 
    private void setFooBar(String fooBar) { 
    this.fooBar = fooBar; 
    } 
} 

Oryginalny problemem jest to, że muszę coś zrobić z OldBar.fooBar, ale oryginalny projekt miał ograniczenia i miał to pole prywatne, co uniemożliwiło mi jego podklasowanie, więc musiałem stworzyć całą inną klasę, NewBar, aby zastąpić drugą klasę i uzyskać dostęp do prywatnego pola. Pomyślałem, że skoro NewBar jest również Embeddable i ma taką samą @Column oznaczenie, może po prostu zamienić na pole w klasie Foo:

private NewBar bar = new NewBar(); 

chciałem tego robić, bo mam istniejących danych w kolumnie foobar i Chciałem użyć tych danych w przejrzysty sposób, używając NewBar zamiast OldBar.

Dzięki dziennikom śledzenia widziałem, że Foo() jest tworzony z domyślną wersją NewBar(), jak można się spodziewać, po wywołaniu konstruktora. Jednak do czasu kod Foo.getBar(), z jakiegoś powodu bar jest null! Przypuszczam, że Hibernate ustawia z jakiegoś powodu na null - ale dlaczego nie jest w stanie hibernacji czytając dane z kolumny foobar i tworząc instancję NewBar? Dlaczego znowu działa, gdy ponownie wstawiam OldBar zamiast ? Z pewnością w bazie danych nie ma informacji, która z klas @Embeddable jest odwzorowana na kolumnę, czy istnieje?

Aktualizacja: To staje się coraz bardziej nieznajoma. Czasami zostawiam kod na noc, a następnego dnia działa! Lub następnego dnia to nie działa! Właśnie teraz to nie zadziałało (to znaczy, właściwość foobar została ustawiona na null zamiast wartości w bazie danych), więc utworzyłem klasę ExactCopyOfOldBar i ustawiłem ją na miejsce OldBar. Wszystko działało dobrze! Wracam więc do NewBar --- tylko cofam moje tymczasowe zmiany. Nadal działało, kiedy jeszcze nie było! Czy jest jakaś pamięć podręczna, w której Hibernate serializuje wartości i nie pobiera ich z bazy danych? To bardzo dziwne.

Aktualizacja: Teraz nie mogę już uzyskać NewBar do pracy w ogóle. Tworzę OtherBar, która jest w zasadzie identyczna z NewBar, z tą różnicą, że ma inną nazwę, a ja podłączam ją i działa, poprawnie odczytując osadzony ciąg. Wracam na numer NewBar i ponownie otrzymuję numer null. Co się dzieje?

Należy zauważyć, że Foo jest ładowany przez net.databinder.auth.hib.AuthDataApplication.getUser(String username), który jest prosty:

return (DataUser) Databinder.getHibernateSession().createCriteria(getUserClass()) 
    .add(Restrictions.eq("username", username)).uniqueResult(); 

I zostały zweryfikowane przez cały czas, że (użytkownik) Tabela Foo ma jeden wiersz z odpowiednich danych i co najważniejsze, że pole foobar ma dane. Dlaczego funkcja Hibernate przesyła mi Foo z polem nullfoobar? Dlaczego po prostu przełączenie z NewBar na OtherBar powoduje, że zaczyna działać ponownie? Dlaczego to działa przez cały dzień, a potem przestaje działać po tym, jak zostawiłem go na noc?

+0

Zakładam, że to prawda, ale nie powiedziałeś tego: Czy 'Foo.bar' jest oznaczony jako' @ Embedded'? –

+0

@Tim Pote: Rzeczywiście, o dziwo, w oryginalnym (działającym) starszym kodzie, nie było _ oznaczone jako "@ Embedded". Próbowałem go z i bez '@ Embedded', kiedy zmieniłem z' OldBar' na 'NewBar', i to nie miało znaczenia. –

+0

@ Tim Pote: Nauczyłem się z Hibernate [dokumentacja] (http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/), że "... jeśli typ właściwości jest oznaczony jako @Embeddable, jest mapowany jako @Embedded, "więc technicznie część' @ Embedded' jest opcjonalna. –

Odpowiedz

1

To może być odpowiedź; Będę musiał poczekać kilka dni, aby sprawdzić, czy rzeczywiście rozwiązuje problem. W rzeczywistości są dwie części.

Po pierwsze, dla pełnego ujawnienia moja klasa NewBar była w rzeczywistości podklasą AbstractBar. W końcu chciałem mieć różne typy kostek do wstawiania, więc umieściłem @Embeddable na poziomie AbstractBar, nie na poziomie NewBar i umieściłem prywatne pole foobar również na poziomie AbstractBar. Zabawne jest to, że działało to przez jakiś czas. I jak wspomniałem, czasami wracałem następnego dnia, a Hibernate nie ładował pola foobar. Nie rozumiem, dlaczego nie pracował on przez cały czas, ani nie pracował w żadnym momencie.

Po drugie, kiedy starałem się pozbyć tej hierarchii, tak aby wyeliminować jedno źródło problemu, ja conflated AbstractBar i NewBar ale zapomniał przynieść @Embeddable się z AbstractBar do NewBar, więc Hibernate nie widział, że było klasa embedable i nie wiedział, jak załadować łańcuch znaków do pola NewBar bez oznaczenia @Embeddable. Z tego powodu zadziałał OtherBar (z adnotacją @Embeddable), ale nie NewBar (bez adnotacji @Embeddable). Tyle rozumiem. Dlaczego Hibernate nie ostrzegł mnie, że nie może dowiedzieć się, jak załadować pole, nie wiem.

Podsumowując, Hibernate nie załaduje pola do osadzenia, jeśli pozostawiłeś adnotację @Embeddable poza zajęciami. Jeśli chodzi o pierwotny problem, mogę tylko zgadywać, że @Embeddable jest niestabilny, gdy próbuje go użyć w hierarchii klas, i że najlepiej jest trzymać wszystkie swoje osadzalne pola na jednym poziomie w klasie embedable. Mam nadzieję, że to jest problem. Zobaczymy, czy będzie działać jutro.