Hibernuj adnotacje - co jest lepsze, dostęp do pola lub właściwości?

Odpowiedzi:

33

Preferuję akcesory, ponieważ mogę dodać logikę biznesową do moich akcesorów, kiedy tylko potrzebuję. Oto przykład:

@Entity
public class Person {

  @Column("nickName")
  public String getNickName(){
     if(this.name != null) return generateFunnyNick(this.name);
     else return "John Doe";
  }
}

Poza tym, jeśli wrzucisz inne biblioteki do miksu (np. Niektóre biblioteki konwertujące JSON lub BeanMapper lub Dozer lub inne biblioteki mapowania / klonowania fasoli oparte na właściwościach getter / setter), będziesz mieć gwarancję, że biblioteka jest zsynchronizowana z trwałością manager (oba używają getter / setter).

Miguel Ping
źródło
17
Zwróć uwagę, że chodzi o to, w jaki sposób ORM uzyskuje dostęp do pól / właściwości, a nie do kodu aplikacji. Dzięki dostępowi do pola Twoja metoda getNickName () działałaby dokładnie tak, jak tego oczekujesz. To samo nie jest prawdą, jeśli używasz trwałych „właściwości” poza metodami pobierającymi / ustawiającymi. W tym miejscu mogą wystąpić problemy z dostępem do właściwości i leniwym ładowaniem. Więc nie, ogólnie nie zgadzam się z tym argumentem. Jednak ostatnim razem, gdy sprawdzałem, Hibernate ma problemy z dostępem do pól @Id.
Rob Bygrave
11
ta odpowiedź nie jest związana z pytaniem. Najlepsza odpowiedź od duffymo
Janning,
9
nie powinno być żadnej logiki biznesowej wewnątrz akcesorów. to nie jest oczywiste zachowanie.
iuriisusuk
Dlaczego ta odpowiedź jest oznaczona jako poprawna? Nie jest prawdą, że możesz odwzorować pole i w ten sam sposób nadać mu setter / getter.
Lucke
246

Istnieją argumenty przemawiające za jednym i drugim, ale większość z nich wynika z pewnych wymagań użytkownika „a co, jeśli trzeba dodać logikę dla” lub „xxxx przerywa hermetyzację”. Jednak nikt tak naprawdę nie skomentował tej teorii i nie podał odpowiednio uzasadnionego argumentu.

Co właściwie robi Hibernate / JPA, gdy utrzymuje obiekt - cóż, utrwala STAN obiektu. Oznacza to przechowywanie go w taki sposób, aby można go było łatwo odtworzyć.

Co to jest hermetyzacja? Enkapsulacja oznacza hermetyzację danych (lub stanu) za pomocą interfejsu, z którego aplikacja / klient może korzystać w celu bezpiecznego dostępu do danych - zachowując ich spójność i aktualność.

Pomyśl o tym jak o MS Word. MS Word przechowuje w pamięci model dokumentu - STAN dokumentów. Przedstawia interfejs, za pomocą którego użytkownik może modyfikować dokument - zestaw przycisków, narzędzi, poleceń klawiaturowych itp. Jeśli jednak zdecydujesz się utrwalić (Zapisz) ten dokument, zapisuje stan wewnętrzny, a nie zestaw naciśnięć klawiszy i kliknięcia myszą użyte do jego wygenerowania.

Zapisywanie stanu wewnętrznego obiektu NIE przerywa enkapsulacji - w przeciwnym razie nie rozumiesz, co oznacza hermetyzacja i dlaczego istnieje. To jest tak, jak w rzeczywistości serializacja obiektów.

Z tego powodu W WIĘKSZOŚCI PRZYPADKÓW właściwe jest utrzymanie PÓL, a nie AKCESORÓW. Oznacza to, że obiekt można dokładnie odtworzyć z bazy danych dokładnie tak, jak był przechowywany. Nie powinno wymagać żadnej walidacji, ponieważ zostało to zrobione na oryginale, gdy został utworzony, a zanim został zapisany w bazie danych (chyba, że ​​nie daj Boże, przechowujesz nieprawidłowe dane w DB !!!!). Podobnie nie powinno być potrzeby obliczania wartości, ponieważ zostały one obliczone przed zapisaniem obiektu. Obiekt powinien wyglądać tak, jak przed zapisaniem. W rzeczywistości, dodając dodatkowe rzeczy do getterów / seterów, w rzeczywistości zwiększasz ryzyko, że odtworzysz coś, co nie jest dokładną kopią oryginału.

Oczywiście ta funkcjonalność została dodana nie bez powodu. Mogą istnieć pewne ważne przypadki użycia utrwalania metod dostępu, jednak zazwyczaj będą one rzadkie. Przykładem może być to, że chcesz uniknąć utrwalania obliczonej wartości, chociaż możesz zadać pytanie, dlaczego nie obliczasz jej na żądanie w getterze wartości, lub leniwie inicjujesz ją w getterze. Osobiście nie mogę wymyślić żadnego dobrego przypadku użycia, a żadna z odpowiedzi tutaj nie daje odpowiedzi „Inżynierii oprogramowania”.

Jaskółka oknówka
źródło
9
Odpowiedź inżynierii oprogramowania brzmi: używanie akcesorów narusza DRY.
sourcedelica
1
@Martin Mam dodatkowe pytanie dotyczące ostatniego akapitu Twojej odpowiedzi. Napisałeś „Przykładem może być to, że chcesz uniknąć utrwalania obliczonej wartości”. Jak uniknąć utrwalania obliczonej wartości, mając dostęp oparty na właściwościach? Wiem, że spierasz się, aby tego nie robić, ale nie rozumiem tego. Czy możesz wyjaśnić?
Geek
4
@Geek Teraz, kiedy to przeczytałem, sam nie jestem do końca pewien. Minęły dwa lata, odkąd napisałem tę odpowiedź. Myślę, że lepszym przykładem może być sytuacja, w której pracujesz ze starszą bazą danych, a dane są prezentowane w inny sposób niż model obiektowy - akcesory mogą zapewnić mapowanie między nimi.
Martin
23
Dobrym przypadkiem użycia mapowania akcesorów jest dodanie informacji o mapowaniu do podklas klas jednostek innych firm, które nie są powiązane z żadną implementacją trwałości. Ponieważ pola w tych klasach są prywatne, musisz przesłonić metody dostępu i dodać do nich adnotacje mapujące. Inną opcją byłoby użycie mapowania XML, ale niektóre rzeczy są tam bardzo trudne. Tak więc, jeśli chcesz adnotacji i mapować klasy innych firm, najlepszym rozwiązaniem jest tworzenie podklas i dodawanie adnotacji na akcesoriach.
Elnur Abdurrakhimov
5
@ElnurAbdurrakhimov, oto doskonały przykład. Dzięki.
Martin
79

Preferuję dostęp do pola, ponieważ w ten sposób nie jestem zmuszony do dostarczania getter / setter dla każdej właściwości.

Szybka ankieta przeprowadzona przez Google sugeruje, że dostęp do terenów stanowi większość (np. Http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype ).

Uważam, że dostęp do pola jest idiomem zalecanym przez Spring, ale nie mogę znaleźć odniesienia, aby to potwierdzić.

Istnieje powiązane pytanie SO, które próbowało zmierzyć wydajność i doszło do wniosku, że „nie ma różnicy”.

duffymo
źródło
jeśli nie dostarczysz settera pobierającego w encji, to jaki jest pożytek z tego pola ... nie możesz go użyć nigdzie w aplikacji, ponieważ pola są prywatne
anshulkatta
1
Czy zapewnienie gettera i setera dla twoich pól nie jest złą praktyką? Myślę, że mój komentarz tutaj nie zawsze jest właściwy, ponieważ zakładałem pole publiczne, podczas gdy oczywiście może to być pole prywatne, do którego nigdy nie uzyskano dostępu.
Mathijs Segers
3
@anshulkatta Myślę, że naprawdę powinienem odpowiedzieć na Twoje pytania, ponieważ na tym właśnie polega hermetyzacja. Idealnie wszystkie twoje pola powinny być prywatne i jeśli to możliwe, nie powinny mieć żadnych pobierających ani ustawiających - to najlepszy poziom enkapsulacji, na jaki możesz liczyć. Rozważ narzędzie do sprawdzania haseł. 2 pola prywatne passwordHash i failedAttempts. Obie mogą być prywatne bez pobierania lub ustawiania. Są one używane przez bool checkPassword (hasło w postaci ciągu znaków), które haszuje, sprawdza hasłem passwordHash, a następnie aktualizuje nieudane próby i zwraca wynik. Nie ma potrzeby stosowania innego kodu, aby uzyskać dostęp do tych dwóch pól.
Martin
2
@anshulkatta należy zauważyć, że w OOP, metody pobierające i ustawiające są anty-wzorcem, pochodzą z programowania proceduralnego, posiadanie klasy z nimi łamie zasadę hermetyzacji i generuje dużo kodu standardowego, czyli tego samego rodzaju kod powtarzany w kółko. Obiekty powinny być niezmienne, jeśli wymagana jest modyfikacja ich właściwości, należy to zrobić metodą, która robi coś więcej niż tylko zwrócenie wartości właściwości.
Uriel Arvizu
Skąd. „Anty-wzór” w tym przypadku to kwestia opinii, a nie dogmatu. W związku z tym dostęp w terenie jest nadal preferowany. Lepszym pomysłem jest całkowite unikanie rozwiązań ORM. Naucz się pisać poprawne SQL.
duffymo
38

Oto sytuacja, w której MUSISZ użyć metod dostępu do właściwości. Wyobraź sobie, że masz klasę abstrakcyjną GENERIC z wieloma dobrymi implementacjami, które można dziedziczyć w 8 konkretnych podklasach:

public abstract class Foo<T extends Bar> {

    T oneThing;
    T anotherThing;

    // getters and setters ommited for brevity

    // Lots and lots of implementation regarding oneThing and anotherThing here
 }

Teraz dokładnie, jak należy opisać tę klasę? Odpowiedź brzmi: NIE MOŻESZ w ogóle dodawać adnotacji do pola lub właściwości, ponieważ w tym momencie nie możesz określić jednostki docelowej. MUSISZ opisać konkretne implementacje. Ale ponieważ utrwalone właściwości są zadeklarowane w tej nadklasie, MUSISZ użyć dostępu do właściwości w podklasach.

Dostęp do pola nie jest opcją w aplikacji z abstrakcyjnymi ogólnymi superklasami.

HDave
źródło
2
dotykać. Nie pomyślałem o tym. Założę się, że Hibernate wykopuje dla nich szalony sql.
Joseph Lust
8
Ten problem wydaje się trudny do rozwiązania mechanicznego bez opisywania właściwości, ale nigdy nie spotkałem się z przypadkiem, w którym potrzebowałem abstrakcyjnej klasy ogólnej z dużą ilością implementacji, którą również chciałem utrzymać. Zazwyczaj tworzę hierarchię klas, aby uczynić mój obiekt polimorficznym (co czyni go ogólnym rodzajem przerw), a nie tylko w celu ponownego wykorzystania kodu. A „wiele, wiele implementacji” i tak często narusza SRP, w takim przypadku prawdopodobnie przeniósłbym go do oddzielnych klas. Czy istnieje konkretny przykład, który sprawia, że ​​ten przypadek użycia jest bardziej oczywisty?
Merlyn Morgan-Graham
Jedynym konkretnym przykładem, jaki mam, jest moja aplikacja, której nie mogę opisać w komentarzu na 500 znaków ;-)
HDave
3
Możesz używać abstract T getOneThing()i abstract void setOneThing(T thing), i używać dostępu do pola.
Arturo Volpe
33

Preferuję i używam akcesorów własności:

  • Mogę dodać logikę, jeśli zajdzie taka potrzeba (jak wspomniano w zaakceptowanej odpowiedzi).
  • pozwala mi dzwonić foo.getId() bez inicjowania proxy (ważne przy używaniu Hibernacji, dopóki HHH-3718 nie zostanie rozwiązany).

Wada:

  • sprawia, że ​​kod jest mniej czytelny, musisz na przykład przeglądać całą klasę, aby zobaczyć, czy są w @Transientpobliżu.
Pascal Thivent
źródło
ale jeśli korzystasz z dostawcy JPA, który nie ma „serwerów proxy”, nie masz tego problemu, czyli „narzuca ci to dostawca JPA”.
Neil Stockton
13

To naprawdę zależy od konkretnego przypadku - obie opcje są dostępne z jakiegoś powodu. IMO sprowadza się do trzech przypadków:

  1. setter ma pewną logikę, która nie powinna być wykonywana w czasie ładowania instancji z bazy danych; na przykład pewna walidacja wartości zachodzi w seterze, jednak dane pochodzące z db powinny być prawidłowe (w przeciwnym razie nie dotarłyby tam (:); w tym przypadku dostęp do pola jest najbardziej odpowiedni;
  2. setter ma pewną logikę, która powinna być zawsze wywoływana, nawet podczas ładowania instancji z bazy danych; na przykład inicjalizowana właściwość jest używana do obliczania jakiegoś pola obliczeniowego (np. właściwość - kwota pieniężna, obliczona właściwość - łącznie kilka właściwości pieniężnych tej samej instancji); w takim przypadku wymagany jest dostęp do nieruchomości.
  3. Żaden z powyższych przypadków - wtedy obie opcje mają zastosowanie, po prostu bądź konsekwentny (np. Jeśli dostęp do pola jest wyborem w tej sytuacji to używaj go cały czas w podobnej sytuacji).
01es
źródło
Jestem nowy w Hibernate i zmagam się z tym samym pytaniem. Myślę, że ten post dostarcza najbardziej jasnej odpowiedzi. Dziękuję Ci.
Sam Levin,
12

Zdecydowanie zalecałbym dostęp do pól i NIE adnotacje na elementach pobierających (dostęp do właściwości), jeśli chcesz zrobić coś więcej w ustawiaczach niż tylko ustawienie wartości (np. Szyfrowanie lub obliczenia).

Problem z dostępem do właściwości polega na tym, że metody ustawiające są również wywoływane podczas ładowania obiektu. To działało dobrze przez wiele miesięcy, dopóki nie chcieliśmy wprowadzić szyfrowania. W naszym przypadku chcieliśmy zaszyfrować pole w seterze i odszyfrować je w getterze. Problem z dostępem do właściwości polegał teraz na tym, że gdy Hibernate ładował obiekt, wywoływał on również ustawiającego w celu wypełnienia pola, a tym samym ponownie szyfrował zaszyfrowaną wartość. W tym poście wspomniano również o tym: Java Hibernate: Różne zachowanie funkcji zestawu właściwości w zależności od tego, kto ją wywołuje

Przyprawiało mnie to o ból głowy, dopóki nie przypomniałem sobie różnicy między dostępem do pola a dostępem do nieruchomości. Teraz przeniosłem wszystkie moje adnotacje z dostępu do właściwości do dostępu do pól i teraz działa dobrze.

Christoph
źródło
Tak - zauważyłem, że jeśli używasz dostępu do właściwości, naprawdę nie możesz zrobić nic w swoim seterze poza ustawieniem wartości pola.
HDave
2
+1 Trzymaj się z dala od pobierających / ustawiających. Używam projectlombok.org i ukrywam je przed programistami.
bhantol
11

Wolę korzystać z dostępu do pola z następujących powodów:

  1. Dostęp nieruchomość może prowadzić do bardzo nieprzyjemnych błędów przy wdrażaniu równe / hashCode i przedstawieniu pola bezpośrednio (a nie poprzez ich pobierające). Dzieje się tak, ponieważ proxy jest inicjowane tylko wtedy, gdy uzyskiwany jest dostęp do metod pobierających, a dostęp do pola bezpośredniego zwróciłby po prostu wartość null.

  2. Dostęp nieruchomość wymaga opisywanie wszystkich metod użytkowych (np addChild / removeChild) jako @Transient.

  3. Dzięki dostępowi do pola możemy ukryć pole @Version, nie ujawniając w ogóle metody pobierającej. Getter może również prowadzić do dodania settera, a versionpole nigdy nie powinno być ustawiane ręcznie (co może prowadzić do bardzo nieprzyjemnych problemów). Cała inkrementacja wersji powinna być wyzwalana przez jawne blokowanie OPTIMISTIC_FORCE_INCREMENT lub PESSIMISTIC_FORCE_INCREMENT .

Vlad Mihalcea
źródło
1. W jaki sposób strategia dostępu do terenów temu zapobiega? Wydaje się, że jest to ogólna pułapka w przypadku serwerów proxy, niezależnie od stylu dostępu. 2. Czy na pewno powinny to być tylko programy pobierające narzędzia? (ale i tak dobry argument). 3. Uwidacznianie metod dostępu dla versionpola jest często przydatne w sytuacjach, w których używane są DTO zamiast odłączonych jednostek.
Dragan Bozanovic
1. Z powodu inicjalizacji proxy. 2. 100% pewności. 3. To ważny punkt.
Vlad Mihalcea
Przepraszam za moją ignorancję i możliwy brak interpretacji tekstu (nie jestem ojczystym językiem angielskim). Dla wyjaśnienia, dostęp do pola ma miejsce, gdy żadne metody pobierające / ustawiające nie są potrzebne, więc w przypadku POJO, które jest używane holistycznie, pola są publiczne? Ale mówisz coś w pierwszym temacie, a link do wpisu na blogu mówi inaczej. Zrozumiałem, że nie możesz używać równych przy korzystaniu z serwerów proxy i dostępu do pola.
MaikoID
Nie. Dostęp do pola oznacza, że ​​Hibernate wykorzystuje pola poprzez odbicia do odczytywania atrybutów encji. Aby uzyskać więcej informacji, zapoznaj się z sekcją Typ dostępu w Podręczniku użytkownika hibernacji .
Vlad Mihalcea
7

Myślę, że dodawanie adnotacji do właściwości jest lepsze, ponieważ aktualizowanie pól bezpośrednio przerywa hermetyzację, nawet jeśli robi to Twój ORM.

Oto świetny przykład tego, gdzie cię to spali: prawdopodobnie chcesz, aby adnotacje dla walidatora hibernacji i trwałości znajdowały się w tym samym miejscu (pola lub właściwości). Jeśli chcesz przetestować walidacje oparte na hibernacji walidatora, które są opatrzone adnotacjami w polu, nie możesz użyć makiety swojej encji, aby wyodrębnić test jednostkowy tylko do walidatora. Auć.

Justin Standard
źródło
2
Dlatego umieszczasz adnotacje walidatora na akcesoriach i adnotacjach trwałości na polach
fishbone
6

Uważam, że dostęp do właściwości a dostęp do pola jest nieco inny w odniesieniu do leniwej inicjalizacji.

Rozważ następujące mapowania dla 2 podstawowych fasoli:

<hibernate-mapping package="org.nkl.model" default-access="field">
  <class name="FieldBean" table="FIELD_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

<hibernate-mapping package="org.nkl.model" default-access="property">
  <class name="PropBean" table="PROP_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

Oraz następujące testy jednostkowe:

@Test
public void testFieldBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    FieldBean fb = new FieldBean("field");
    Long id = (Long) session.save(fb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    fb = (FieldBean) session.load(FieldBean.class, id);
    System.out.println(fb.getId());
    tx.commit();
    session.close();
}

@Test
public void testPropBean() {
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    PropBean pb = new PropBean("prop");
    Long id = (Long) session.save(pb);
    tx.commit();
    session.close();

    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    pb = (PropBean) session.load(PropBean.class, id);
    System.out.println(pb.getId());
    tx.commit();
    session.close();
}

Zobaczysz subtelną różnicę w wymaganym wyborze:

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        FIELD_BEAN
        (message, id) 
    values
        (?, ?)
Hibernate: 
    select
        fieldbean0_.id as id1_0_,
        fieldbean0_.message as message1_0_ 
    from
        FIELD_BEAN fieldbean0_ 
    where
        fieldbean0_.id=?
0
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        PROP_BEAN
        (message, id) 
    values
        (?, ?)
1

Oznacza to, że dzwonienie fb.getId()wymaga wybrania, podczas pb.getId()gdy nie.

zestaw narzędzi
źródło
To jest zabawne! :) Ale jestem pewien, że jest to zachowanie specyficzne dla implementacji. I
Vladimir Dyuzhev
Tak, wydaje mi się, że jest to spowodowane faktem, że instrumentami są tylko klasy trwałe. Szkoda jednak, ponieważ pole id jest często tym polem, które nie ma wartości biznesowej i nie potrzebuje żadnego akcesorium.
Maurice Perry,
6

Spróbuję podsumować najważniejsze powody wyboru dostępu w terenie. Jeśli chcesz zanurkować głębiej, przeczytaj ten artykuł na moim blogu: Strategie dostępu w JPA i hibernacji - co jest lepsze, dostęp do pola lub nieruchomości?

Dostęp w terenie jest zdecydowanie lepszą opcją. Oto 5 powodów:

Powód 1: Lepsza czytelność twojego kodu

Jeśli korzystasz z dostępu opartego na polach, opisujesz atrybuty encji za pomocą adnotacji mapowania. Umieszczając definicję wszystkich atrybutów encji na początku swojej klasy, uzyskujesz stosunkowo zwarty widok wszystkich atrybutów i ich mapowań.

Powód 2: Pomiń metody pobierające lub ustawiające, które nie powinny być wywoływane przez aplikację

Kolejną zaletą dostępu opartego na polach jest to, że Twój dostawca trwałości, np. Hibernate lub EclipseLink, nie używa metod pobierających i ustawiających atrybutów encji. Oznacza to, że nie musisz podawać żadnej metody, której nie powinien używać kod Twojej firmy. Dzieje się tak najczęściej w przypadku metod ustawiających generowane atrybuty klucza podstawowego lub kolumny wersji. Twój dostawca trwałości zarządza wartościami tych atrybutów i nie należy ustawiać ich programowo.

Powód 3: Elastyczna implementacja metod pobierających i ustawiających

Ponieważ Twój dostawca trwałości nie wywołuje metod pobierających i ustawiających, nie są one zmuszane do spełnienia żadnych wymagań zewnętrznych. Możesz zaimplementować te metody w dowolny sposób. Dzięki temu można zaimplementować reguły walidacji specyficzne dla firmy, wyzwolić dodatkową logikę biznesową lub przekonwertować atrybut jednostki na inny typ danych.

Możesz na przykład użyć tego do zawijania opcjonalnego skojarzenia lub atrybutu w Javie Optional.

Powód 4: Nie ma potrzeby oznaczania metod użytkowych jako @Transient

Inną zaletą strategii dostępu opartego na polach jest to, że nie musisz dodawać adnotacji do metod narzędziowych @Transient. Ta adnotacja informuje dostawcę trwałości, że metoda lub atrybut nie jest częścią trwałego stanu jednostki. A ponieważ w przypadku dostępu do pól trwały stan jest definiowany przez atrybuty encji, implementacja JPA ignoruje wszystkie metody encji.

Powód 5: unikaj błędów podczas pracy z serwerami proxy

Hibernate używa serwerów proxy do leniwie pobieranych skojarzeń do jednego, dzięki czemu może kontrolować inicjalizację tych skojarzeń. Takie podejście działa dobrze w prawie wszystkich sytuacjach. Ale wprowadza niebezpieczną pułapkę, jeśli korzystasz z dostępu opartego na własności.

Jeśli korzystasz z dostępu opartego na właściwościach, Hibernate inicjuje atrybuty obiektu proxy, gdy wywołasz metodę pobierającą. Dzieje się tak zawsze, jeśli używasz obiektu proxy w kodzie biznesowym. Ale całkiem sporo implementacji równań i hashCode uzyskuje bezpośredni dostęp do atrybutów. Jeśli jest to pierwszy raz, gdy uzyskujesz dostęp do któregokolwiek z atrybutów proxy, te atrybuty nadal nie są zainicjowane.

Thorben Janssen
źródło
3

Domyślnie dostawcy JPA uzyskują dostęp do wartości pól encji i mapują te pola na kolumny bazy danych przy użyciu metod dostępu (getter) i mutatora (setter) właściwości JavaBean jednostki. W związku z tym nazwy i typy pól prywatnych w jednostce nie mają znaczenia dla WZP. Zamiast tego JPA sprawdza tylko nazwy i typy zwracane metod dostępu do właściwości JavaBean. Możesz to zmienić za pomocą @javax.persistence.Accessadnotacji, która umożliwia jawne określenie metodologii dostępu, którą powinien stosować dostawca JPA.

@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}

Dostępne opcje wyliczenia AccessType to PROPERTY (wartość domyślna) i FIELD. W przypadku PROPERTY dostawca pobiera i ustawia wartości pól przy użyciu metod właściwości JavaBean. FIELD sprawia, że ​​dostawca pobiera i ustawia wartości pól przy użyciu pól instancji. Najlepszą praktyką jest trzymanie się wartości domyślnych i używanie właściwości JavaBean, chyba że masz istotny powód, aby postąpić inaczej.

Możesz umieścić te adnotacje właściwości w polach prywatnych lub publicznych metodach dostępu. Jeśli używasz AccessType.PROPERTY(domyślnie) i opisujesz pola prywatne zamiast metod dostępu JavaBean, nazwy pól muszą być zgodne z nazwami właściwości JavaBean. Jednak nazwy nie muszą być zgodne, jeśli dodasz adnotacje do metod dostępu JavaBean. Podobnie, jeśli AccessType.FIELDzamiast pól używasz metod dostępu JavaBean i dodasz do nich adnotacje, nazwy pól również muszą być zgodne z nazwami właściwości JavaBean. W takim przypadku nie muszą się one zgadzać, jeśli dodasz adnotacje do pól. Najlepiej jest po prostu zachować spójność i dodawać adnotacje do metod dostępu JavaBean dla AccessType.PROPERTYi pól dla AccessType.FIELD.

Ważne jest, aby nigdy nie mieszać adnotacji właściwości JPA i adnotacji pól JPA w tej samej encji. Takie postępowanie skutkuje nieokreślonym zachowaniem i jest bardzo prawdopodobne, że spowoduje błędy.

Faraz
źródło
2

Czy już dotarliśmy

To stara prezentacja, ale Rod sugeruje, że adnotacje dotyczące dostępu do właściwości zachęcają do anemicznych modeli domen i nie powinny być „domyślnym” sposobem tworzenia adnotacji.

Manuel Palacio
źródło
2

Innym argumentem przemawiającym za dostępem do pola jest to, że w przeciwnym razie jesteś zmuszony ujawniać setery dla kolekcji, co dla mnie jest złym pomysłem, ponieważ zmiana instancji trwałej kolekcji na obiekt nie zarządzany przez Hibernate z pewnością zepsuje spójność danych.

Dlatego wolę mieć kolekcje jako chronione pola zainicjowane do pustych implementacji w domyślnym konstruktorze i ujawniać tylko ich metody pobierające. Wtedy tylko operacje zarządzane, takie jakclear() , remove(), removeAll()możliwe, że nigdy nie będzie Hibernate są nieświadomi zmian itp.

Jiří Vypědřík
źródło
Nie musisz niczego ujawniać, bo setery mogą być chronione. Również te setery nie są częścią implementowanego interfejsu, więc nawet jeśli byłyby publiczne, nie są łatwo dostępne.
HDave
2

Preferuję pola, ale napotkałem jedną sytuację, która wydaje się zmuszać mnie do umieszczania adnotacji na getterach.

Z implementacją Hibernate JPA, @Embeddedwydaje się , że nie działa na polach. Więc to musi iść dalej. A kiedy już umieścisz to w getterze, wtedy różne @Columnadnotacje też muszą trafić do getterów. (Myślę, że Hibernate nie chce tutaj mieszać pól i getterów). A kiedy @Columnjuż umieścisz gettery w jednej klasie, prawdopodobnie ma to sens.


źródło
2

Preferuję akcesoria do pól. Kod jest znacznie bardziej przejrzysty. Wszystkie adnotacje można umieścić w jednej sekcji klasy, a kod jest znacznie łatwiejszy do odczytania.

Znalazłem inny problem z metodami dostępu do właściwości: jeśli masz metody getXYZ w swojej klasie, które NIE są przypisane do trwałych właściwości, hibernacja generuje sql, aby spróbować uzyskać te właściwości, co powoduje pewne bardzo mylące komunikaty o błędach. Zmarnowane dwie godziny. Nie napisałem tego kodu; W przeszłości zawsze korzystałem z metod dostępu do pól i nigdy nie napotkałem tego problemu.

Wersje hibernacji używane w tej aplikacji:

<!-- hibernate -->
<hibernate-core.version>3.3.2.GA</hibernate-core.version>
<hibernate-annotations.version>3.4.0.GA</hibernate-annotations.version>
<hibernate-commons-annotations.version>3.1.0.GA</hibernate-commons-annotations.version>
<hibernate-entitymanager.version>3.4.0.GA</hibernate-entitymanager.version>
John Goyer
źródło
2

Należy wybrać dostęp za pośrednictwem pól zamiast dostępu za pośrednictwem właściwości. Za pomocą pól możesz ograniczyć ilość wysyłanych i odbieranych danych. Dzięki właściwościom możesz wysłać więcej danych jako host i ustawić nominały G (które fabrycznie ustawiają w sumie większość właściwości).

user10801787
źródło
1

Miałem to samo pytanie dotyczące typu dostępu w trybie hibernacji i znalazłem tutaj kilka odpowiedzi .

zegar słoneczny
źródło
1

Stworzyliśmy fasolki encji i użyliśmy adnotacji pobierających. Problem, który napotkaliśmy, jest następujący: niektóre encje mają złożone reguły dotyczące niektórych właściwości, określające, kiedy można je zaktualizować. Rozwiązaniem było posiadanie logiki biznesowej w każdym programie ustawiającym, która określa, czy rzeczywista wartość uległa zmianie, a jeśli tak, to czy zmiana powinna być dozwolona. Oczywiście Hibernate zawsze może ustawić właściwości, więc otrzymaliśmy dwie grupy ustawiaczy. Dość brzydki.

Czytając poprzednie posty, widzę również, że odwoływanie się do właściwości z wnętrza jednostki może prowadzić do problemów z ładowaniem kolekcji.

Podsumowując, skłaniałbym się do dodawania adnotacji do pól w przyszłości.

Steve11235
źródło
0

Zwykle fasola to POJO, więc i tak mają akcesory.

Zatem pytanie nie brzmi „który jest lepszy?”, Ale po prostu „kiedy używać dostępu do pola?”. A odpowiedź brzmi: „kiedy nie potrzebujesz ustawiacza / pobierającego dla pola!”.

Vladimir Dyuzhev
źródło
4
Problem polega na tym, że nie można mieszać dostępu do pola i dostępu do nieruchomości w POJO - musisz wybrać jedno
Martin OConnor,
Naprawdę? Musiałem o tym zapomnieć. W każdym razie zawsze używam POJO i akcesorów.
Vladimir Dyuzhev
Zauważ, że w przypadku JPA 2.0 (którego nie było w pobliżu, gdy zadawano to pytanie) możesz teraz mieszać typy dostępu za pomocą adnotacji @AccessType.
mtpettyp
0

myślę o tym i wybieram metodę accesor

czemu?

ponieważ pole i metoda accesor są takie same, ale jeśli później będę potrzebować logiki w polu ładowania, zapisuję przenieść wszystkie adnotacje umieszczone w polach

pozdrowienia

Grubharta

user261548
źródło
0

Aby uczynić swoje klasy czystszymi, umieść adnotację w polu, a następnie użyj @Access (AccessType.PROPERTY)

ely
źródło
0

AccessType.PROPERTY: implementacja trwałości EJB załaduje stan do Twojej klasy za pośrednictwem metod „ustawiających” w języku JavaBean i pobierze stan z klasy za pomocą metod „pobierających” języka JavaBean. To jest ustawienie domyślne.

AccessType.FIELD: Stan jest ładowany i pobierany bezpośrednio z pól Twojej klasy. Nie musisz pisać "getters" i "setters" JavaBean.

Daria Yu
źródło