Annota le ibernazioni - Qual è l'accesso migliore, sul campo o alla proprietà?


Risposte:


33

Preferisco gli accessori, poiché posso aggiungere alcune logiche aziendali ai miei accessori ogni volta che ne ho bisogno. Ecco un esempio:

@Entity
public class Person {

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

Inoltre, se lanci un'altra libreria nel mix (come alcune librerie convertite in JSON o BeanMapper o Dozer o altre librerie / clonazioni di bean basate su proprietà getter / setter) avrai la garanzia che la libreria è sincronizzata con la persistenza manager (entrambi usano il getter / setter).


17
Nota che questo riguarda il modo in cui ORM accede ai tuoi campi / proprietà e non al codice dell'applicazione. Con l'accesso ai campi il tuo metodo getNickName () funzionerebbe esattamente come ti aspetteresti. Lo stesso non è vero se si usano le 'proprietà' persistenti al di fuori dei getter / setter. È qui che potresti riscontrare problemi con l'accesso alla proprietà e il caricamento lento. Quindi no, non sono d'accordo con questo argomento in generale. Tuttavia, l'ultima volta che ho controllato Hibernate ha avuto problemi con l'accesso ai campi dei campi @Id.
Rob Bygrave,

11
questa risposta non è correlata alla domanda. Migliore risposta di duffymo
Janning,

9
non dovrebbe esserci alcuna logica aziendale all'interno degli accessori. non è un comportamento ovvio.
Iuriisusuk,

Perché questo segno di risposta è corretto? Non è vero che puoi mappare il campo e fornirgli un setter / getter allo stesso modo.
Fortuna,

246

Ci sono argomenti per entrambi, ma la maggior parte di essi deriva da determinati requisiti dell'utente "che cosa succede se è necessario aggiungere la logica per" o "incapsulamento delle interruzioni xxxx". Tuttavia, nessuno ha veramente commentato la teoria e dato un argomento adeguatamente ragionato.

Cosa sta realmente facendo Hibernate / JPA quando persiste un oggetto - beh, sta persistendo lo STATO dell'oggetto. Ciò significa memorizzarlo in modo che possa essere facilmente riprodotto.

Che cos'è l'incapsulamento? Incapsulamento significa incapsulare i dati (o lo stato) con un'interfaccia che l'applicazione / client può utilizzare per accedere ai dati in modo sicuro, mantenendoli coerenti e validi.

Pensa a questo come a MS Word. MS Word mantiene in memoria un modello del documento: i documenti STATE. Presenta un'interfaccia che l'utente può utilizzare per modificare il documento: una serie di pulsanti, strumenti, comandi da tastiera ecc. Tuttavia, quando si sceglie di persistere (Salva) quel documento, salva lo stato interno, non l'insieme di pressioni di tasti e clic del mouse utilizzati per generarlo.

Salvare lo stato interno dell'oggetto NON rompe l'incapsulamento, altrimenti non si capisce veramente cosa significa incapsulamento e perché esiste. È proprio come la serializzazione degli oggetti.

Per questo motivo, NELLA MAGGIOR PARTE DEI CASI, è opportuno persistere nei CAMPI e non negli ACCESSORI. Ciò significa che un oggetto può essere ricreato con precisione dal database esattamente come è stato archiviato. Non dovrebbe aver bisogno di alcuna convalida, perché questo è stato fatto sull'originale al momento della sua creazione e prima che fosse archiviato nel database (a meno che, Dio non voglia, stai memorizzando dati non validi nel DB !!!!). Allo stesso modo, non dovrebbe essere necessario calcolare i valori, poiché erano già stati calcolati prima che l'oggetto fosse archiviato. L'oggetto dovrebbe apparire esattamente come prima di essere salvato. In effetti, aggiungendo elementi aggiuntivi nei getter / setter, si aumenta effettivamente il rischio di ricreare qualcosa che non è una copia esatta dell'originale.

Naturalmente, questa funzionalità è stata aggiunta per un motivo. Potrebbero esserci alcuni casi d'uso validi per il persistere degli accessori, tuttavia, saranno in genere rari. Un esempio potrebbe essere quello di evitare di persistere in un valore calcolato, anche se è possibile porre la domanda sul perché non lo si calcola su richiesta nel getter del valore, oppure inizializzarlo pigramente nel getter. Personalmente non riesco a pensare ad alcun buon caso d'uso, e nessuna delle risposte qui dà davvero una risposta "Ingegneria del software".


9
La risposta di ingegneria del software è: l'utilizzo degli accessi viola il DRY.
sourcedelica,

1
@Martin Ho una domanda di follow-up sull'ultimo paragrafo della tua risposta. Hai scritto "Un esempio potrebbe essere che vuoi evitare di persistere in un valore calcolato". Come evitare il persistere di un valore calcolato avendo accesso basato sulla proprietà? So che stai discutendo di non farlo, ma non capisco il punto qui. Puoi spiegare per favore?
Geek,

4
@Geek Ora che ho letto di nuovo non sono del tutto sicuro di me stesso. Sono passati due anni da quando ho scritto questa risposta. Immagino che un esempio migliore potrebbe essere quello in cui stai lavorando con un database legacy e i dati sono presentati in modo diverso rispetto al tuo modello a oggetti: gli accessor potrebbero fornire una mappatura tra i due.
Martin,

23
Un buon caso d'uso per gli accessori di mappatura è quando è necessario aggiungere informazioni di mappatura a sottoclassi di classi di entità di terze parti che non sono legate a nessuna implementazione di persistenza. Poiché i campi sono privati ​​in quelle classi, devi sovrascrivere gli accessor e aggiungere annotazioni di mappatura ad essi. Un'altra opzione sarebbe quella di utilizzare la mappatura XML, ma alcune cose sono molto difficili da fare lì. Quindi, se vuoi annotazioni e mappare classi di terze parti, la sottoclasse e l'aggiunta di annotazioni sugli accessori è la strada da percorrere.
Elnur Abdurrakhimov,

5
@ElnurAbdurrakhimov eccoci, un eccellente esempio. Grazie.
Martin,

79

Preferisco l'accesso ai campi, perché in questo modo non sono costretto a fornire getter / setter per ogni proprietà.

Un rapido sondaggio tramite Google suggerisce che l'accesso sul campo è la maggioranza (ad esempio, http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype ).

Credo che l'accesso sul campo sia il linguaggio raccomandato da Spring, ma non riesco a trovare un riferimento per sostenerlo.

C'è una domanda SO correlata che ha cercato di misurare le prestazioni e ha concluso che "non c'è differenza".


se non fornisci setter getter in entity allora qual è l'uso di quel campo ... non puoi usarlo ovunque nell'applicazione, perché i campi sono privati
anshulkatta

1
Non è una cattiva pratica il tuo getter e setter per i tuoi campi? Immagino che il mio commento qui non sia sempre corretto, dal momento che stavo assumendo un campo pubblico, mentre ovviamente potrebbe essere un campo privato a cui non si accede mai.
Mathijs Segers,

3
@anshulkatta Sento che dovrei davvero rispondere alle tue domande, poiché questo è l'incapsulamento. Idealmente tutti i tuoi campi dovrebbero essere privati ​​e, se possibile, non dovrebbero avere getter o setter - questo è il miglior livello di incapsulamento che puoi sperare. Prendi in considerazione un controllo password. 2 campi privati ​​passwordHash e fallito Tentativi. Entrambi possono essere privati ​​senza getter o setter. Sono usati da bool checkPassword (stringa password) che esegue l'hashing, verifica contro passwordHash e quindi aggiorna fallito. Tenta e restituisce un risultato. Non è necessario che altri codici accedano mai a questi due campi.
Martin,

2
@anshulkatta va notato che in OOP, getter e setter sono un anti-pattern, provengono dalla programmazione procedurale, avere una classe con loro rompe il principio di incapsulamento e genera un sacco di codice boilerplate, cioè lo stesso tipo di codice ripetuto più e più volte. Gli oggetti dovrebbero essere immutabili, se è necessaria la modifica delle sue proprietà, questo dovrebbe essere fatto attraverso un metodo che fa qualcosa di più che restituire semplicemente il valore della proprietà.
Uriel Arvizu,

Non così. "Anti-pattern" in questo caso è una questione di opinione, non di dogma. Detto questo, l'accesso al campo è ancora preferito. Un'idea migliore è quella di evitare del tutto le soluzioni ORM. Scopri come scrivere SQL corretto.
duffymo,

38

Ecco una situazione in cui DEVI utilizzare gli accessori di proprietà. Immagina di avere una classe astratta GENERICA con molta bontà di implementazione da ereditare in 8 sottoclassi concrete:

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
 }

Ora, esattamente come dovresti annotare questa classe? La risposta è che NON PUOI annotarlo affatto con l'accesso al campo o alla proprietà perché non puoi specificare l'entità target a questo punto. DEVI annotare le implementazioni concrete. Ma poiché le proprietà persistenti sono dichiarate in questa superclasse, DEVI usare l'accesso alle proprietà nelle sottoclassi.

L'accesso ai campi non è un'opzione in un'applicazione con superclassi generiche astratte.


2
touche. Non ci avevo pensato. Scommetto che Hibernate butta fuori un pazzo di sql per questi.
Joseph Lust,

8
Questo problema sembra meccanicamente difficile da risolvere senza annotare le proprietà, ma non mi sono mai imbattuto in un caso in cui avevo bisogno di una classe generica astratta con molta implementazione che volevo perseverare. In genere creo una gerarchia di classi per rendere il mio oggetto polimorfico (che lo rende un tipo generico di interruzioni), e non solo per il riutilizzo del codice. E "un sacco di implementazione" spesso viola l'SRP, nel qual caso probabilmente lo sposterei in classi separate. C'è un esempio concreto che rende questo caso d'uso più ovvio?
Merlyn Morgan-Graham,

L'unico esempio concreto che ho è la mia applicazione, che non posso descrivere in un commento di 500 caratteri ;-)
HDave

3
È possibile utilizzare abstract T getOneThing(), abstract void setOneThing(T thing)ee utilizzare l'accesso al campo.
Arturo Volpe,

33

Tendo a preferire e utilizzare gli accessori di proprietà:

  • Posso aggiungere la logica in caso di necessità (come indicato nella risposta accettata).
  • mi permette di chiamare foo.getId() senza inizializzare un proxy (importante quando si utilizza Hibernate, fino a quando HHH-3718 non viene risolto).

Inconveniente:

  • rende il codice meno leggibile, ad esempio devi sfogliare un'intera classe per vedere se ci sono in @Transientgiro.

ma poi se usi un provider JPA che non ha "proxy", allora non hai quel problema noto come "il tuo provider JPA ti sta imponendo".
Neil Stockton,

13

Dipende molto da un caso specifico: entrambe le opzioni sono disponibili per un motivo. IMO si riduce a tre casi:

  1. setter ha alcune logiche che non dovrebbero essere eseguite al momento del caricamento di un'istanza da un database; per esempio, una certa convalida del valore avviene nel setter, tuttavia i dati provenienti da db dovrebbero essere validi (altrimenti non ci arriverebbe (:); in questo caso l'accesso al campo è più appropriato;
  2. setter ha alcune logiche che dovrebbero sempre essere invocate, anche durante il caricamento di un'istanza da db; ad esempio, la proprietà che viene inizializzata viene utilizzata nel calcolo di alcuni campi calcolati (ad esempio proprietà - un importo monetario, proprietà calcolata - un totale di più proprietà monetarie della stessa istanza); in questo caso è richiesto l'accesso alla proprietà.
  3. Nessuno dei casi di cui sopra - quindi entrambe le opzioni sono applicabili, resta coerente (ei se l'accesso al campo è la scelta in questa situazione, utilizzalo sempre in una situazione simile).

Sono nuovo di Hibernate e alle prese con la stessa domanda. Penso che questo post fornisca la risposta più chiara. Grazie.
Sam Levin,

12

Consiglio vivamente l'accesso al campo e NON le annotazioni sui getter (accesso alla proprietà) se si desidera fare qualcosa di più nei setter rispetto alla semplice impostazione del valore (ad es. Crittografia o calcolo).

Il problema con l'accesso alla proprietà è che anche i setter vengono chiamati quando l'oggetto viene caricato. Questo ha funzionato bene per me per molti mesi fino a quando non abbiamo voluto introdurre la crittografia. Nel nostro caso d'uso volevamo crittografare un campo nel setter e decrittografarlo nel getter. Il problema ora con l'accesso alle proprietà era che quando Hibernate caricava l'oggetto, stava anche chiamando il setter per popolare il campo e quindi stava crittografando di nuovo il valore crittografato. Questo post menziona anche questo: Ibernazione Java: comportamento della serie di proprietà diverse a seconda di chi lo chiama

Questo mi ha causato mal di testa fino a quando non ho ricordato la differenza tra accesso al campo e accesso alle proprietà. Ora ho spostato tutte le mie annotazioni dall'accesso alla proprietà all'accesso al campo e ora funziona perfettamente.


Sì, ho scoperto che se usi l'accesso alla proprietà non puoi davvero fare nulla nel tuo setter oltre a impostare il valore del campo.
HDave

2
+1 Tenere lontano da getter / setter. Uso projectlombok.org e li tengo nascosti agli sviluppatori.
Bhantol,

11

Preferisco utilizzare l'accesso al campo per i seguenti motivi:

  1. L' accesso alla proprietà può portare a bug molto cattivi durante l'implementazione di egual / hashCode e il riferimento diretto ai campi (al contrario dei loro getter). Questo perché il proxy viene inizializzato solo quando si accede ai getter e un accesso diretto al campo restituisce semplicemente null.

  2. L' accesso alla proprietà richiede di annotare tutti i metodi di utilità (ad es. AddChild / removeChild) come @Transient.

  3. Con l'accesso al campo possiamo nascondere il campo @Version non esponendo affatto un getter. Un getter può anche portare all'aggiunta di un setter e il versioncampo non dovrebbe mai essere impostato manualmente (il che può portare a problemi molto cattivi). L'incremento della versione deve essere attivato tramite il blocco esplicito OPTIMISTIC_FORCE_INCREMENT o PESSIMISTIC_FORCE_INCREMENT .


1. In che modo la strategia di accesso ai campi impedisce questo? Questa sembra essere una trappola generale con i proxy, indipendentemente dallo stile di accesso. 2. Sei sicuro, dovrebbe essere solo getter di utilità? (ma un buon argomento comunque). 3. Esporre gli accessori per il versioncampo è spesso utile nelle situazioni in cui vengono utilizzati DTO anziché entità distaccate.
Dragan Bozanovic,

1. A causa di quando viene inizializzato un proxy. 2. Sicuro al 100%. 3. Questo è un punto valido.
Vlad Mihalcea,

Perdonate la mia ignoranza e la possibile mancanza di interpretazione del testo (non sono un madrelingua inglese). Giusto per chiarire, l'accesso ai campi è quando non sono necessari metodi getter / setter giusti, quindi per un POJO, che è usato olistico, i campi sono pubblici? Ma dici qualcosa nel primo argomento e il post sul blog collegato dice il contrario. Quello che ho capito è che non puoi usare uguali quando usi proxy e accesso al campo.
MaikoID

No. L'accesso ai campi significa che Hibernate utilizza i campi tramite le riflessioni per leggere gli attributi dell'entità. Per ulteriori dettagli, consultare la sezione Tipo di accesso nella Guida dell'utente di Hibernate .
Vlad Mihalcea,

7

Penso che l'annotazione della proprietà sia migliore perché l'aggiornamento dei campi interrompe direttamente l'incapsulamento, anche quando l'ORM lo fa.

Ecco un ottimo esempio di dove ti brucerà: probabilmente vorrai le tue annotazioni per il validatore in ibernazione e la persistenza nello stesso posto (campi o proprietà). Se si desidera testare le convalide basate sul validatore ibernato che sono annotate su un campo, non è possibile utilizzare una simulazione dell'entità per isolare il test unitario solo sul validatore. Ahia.


2
Ecco perché metti annotazioni di validazione sugli accessor e annotazioni di persistenza sui campi
lisca di pesce

6

Credo che l'accesso alla proprietà rispetto all'accesso al campo sia leggermente diverso rispetto all'inizializzazione pigra.

Considerare i seguenti mapping per 2 bean di base:

<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>

E i seguenti test unitari:

@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();
}

Vedrai la sottile differenza nelle selezioni richieste:

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

Cioè, chiamare fb.getId()richiede una selezione, mentre pb.getId()non lo fa.


Questo è divertente! :) Ma è un comportamento specifico dell'implementazione, ne sono sicuro. I
Vladimir Dyuzhev,

Sì, immagino che ciò sia dovuto al fatto che sono strumentate solo le classi persistenti. È un peccato tuttavia perché il campo ID è spesso l'unico campo che non ha alcun valore aziendale e non avrebbe bisogno di alcun accedente.
Maurice Perry,

6

Vorrei provare a riassumere i motivi più importanti per la scelta dell'accesso basato sul campo. Se vuoi immergerti più in profondità, leggi questo articolo sul mio blog: Strategie di accesso in JPA e Hibernate - Qual è l'accesso migliore, sul campo o sulla proprietà?

L'accesso basato sul campo è di gran lunga l'opzione migliore. Ecco 5 motivi per questo:

Motivo 1: migliore leggibilità del codice

Se si utilizza l'accesso basato sul campo, si annotano gli attributi dell'entità con le annotazioni della mappatura. Posizionando la definizione di tutti gli attributi di entità nella parte superiore della classe, si ottiene una vista relativamente compatta di tutti gli attributi e i relativi mapping.

Motivo 2: omettere metodi getter o setter che non dovrebbero essere chiamati dall'applicazione

Un altro vantaggio dell'accesso basato sul campo è che il provider di persistenza, ad esempio Hibernate o EclipseLink, non utilizza i metodi getter e setter degli attributi dell'entità. Ciò significa che non è necessario fornire alcun metodo che non dovrebbe essere utilizzato dal codice aziendale. Questo è spesso il caso dei metodi setter di attributi di chiave primaria generati o colonne di versione. Il provider di persistenza gestisce i valori di questi attributi e non è necessario impostarli a livello di codice.

Motivo 3: implementazione flessibile dei metodi getter e setter

Poiché il provider di persistenza non chiama i metodi getter e setter, non è obbligato a soddisfare alcun requisito esterno. È possibile implementare questi metodi nel modo desiderato. Ciò consente di implementare regole di convalida specifiche dell'azienda, di attivare ulteriori logiche aziendali o di convertire l'attributo dell'entità in un diverso tipo di dati.

Ad esempio, è possibile utilizzarlo per racchiudere un'associazione o un attributo facoltativo in un Java Optional.

Motivo 4: non è necessario contrassegnare i metodi di utilità come @Transient

Un altro vantaggio della strategia di accesso basata sul campo è che non è necessario annotare i metodi di utilità con @Transient. Questa annotazione indica al provider di persistenza che un metodo o un attributo non fa parte dello stato persistente dell'entità. E poiché con l'accesso al tipo di campo lo stato persistente viene definito dagli attributi dell'entità, l'implementazione JPA ignora tutti i metodi dell'entità.

Motivo 5: evitare i bug quando si lavora con i proxy

Hibernate utilizza i proxy per le associazioni pigramente recuperate in modo da poter controllare l'inizializzazione di queste associazioni. Questo approccio funziona bene in quasi tutte le situazioni. Ma introduce una trappola pericolosa se si utilizza l'accesso basato sulla proprietà.

Se si utilizza l'accesso basato su proprietà, Hibernate inizializza gli attributi dell'oggetto proxy quando si chiama il metodo getter. Questo è sempre il caso se usi l'oggetto proxy nel tuo codice aziendale. Ma parecchie implementazioni uguali e hashCode accedono direttamente agli attributi. Se è la prima volta che accedi a uno degli attributi proxy, questi attributi non sono ancora inizializzati.


3

Per impostazione predefinita, i provider JPA accedono ai valori dei campi entità e mappano tali campi alle colonne del database utilizzando i metodi di accesso (getter) e mutatore (setter) della proprietà JavaBean dell'entità. Pertanto, i nomi e i tipi dei campi privati ​​in un'entità non contano per l'APP. Invece, JPA esamina solo i nomi e i tipi restituiti degli accessori di proprietà JavaBean. È possibile modificarlo utilizzando l' @javax.persistence.Accessannotazione, che consente di specificare esplicitamente la metodologia di accesso che il provider JPA dovrebbe utilizzare.

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

Le opzioni disponibili per l'enumerazione AccessType sono PROPERTY (impostazione predefinita) e FIELD. Con PROPERTY, il provider ottiene e imposta i valori dei campi utilizzando i metodi della proprietà JavaBean. FIELD consente al provider di ottenere e impostare i valori dei campi utilizzando i campi dell'istanza. Come best practice, dovresti semplicemente attenerti all'impostazione predefinita e utilizzare le proprietà JavaBean a meno che tu non abbia un motivo convincente per fare diversamente.

È possibile inserire queste annotazioni delle proprietà sui campi privati ​​o sui metodi di accesso pubblico. Se si utilizza AccessType.PROPERTY(impostazione predefinita) e si annotano i campi privati ​​anziché gli accessori JavaBean, i nomi dei campi devono corrispondere ai nomi delle proprietà JavaBean. Tuttavia, i nomi non devono corrispondere se si annotano gli accessori JavaBean. Allo stesso modo, se si utilizzano AccessType.FIELDe annotano gli accessori JavaBean anziché i campi, anche i nomi dei campi devono corrispondere ai nomi delle proprietà JavaBean. In questo caso, non devono corrispondere se si annotano i campi. È meglio essere coerenti e annotare gli accessor JavaBean AccessType.PROPERTYe i campi per AccessType.FIELD.

È importante non mescolare mai le annotazioni delle proprietà JPA e le annotazioni dei campi JPA nella stessa entità. Ciò comporta un comportamento non specificato ed è molto probabile che causi errori.


2

Siamo arrivati

Questa è una vecchia presentazione, ma Rod suggerisce che l'annotazione sull'accesso alle proprietà incoraggia i modelli di dominio anemici e non dovrebbe essere il modo "predefinito" di annotare.


2

Un altro punto a favore dell'accesso ai campi è che altrimenti sei costretto a esporre setter per le raccolte e ciò che, per me, è una cattiva idea in quanto cambiare l'istanza di raccolta persistente in un oggetto non gestito da Hibernate interromperà sicuramente la coerenza dei dati.

Quindi preferisco avere raccolte come campi protetti inizializzati per svuotare le implementazioni nel costruttore predefinito ed esporre solo i loro getter. Quindi, sono possibili solo operazioni gestite come clear(), ecc. remove(), removeAll()Che non renderanno mai Hibernate ignaro delle modifiche.


Non sei obbligato a esporre nulla in quanto i setter possono essere protetti. Inoltre, questi setter non fanno parte dell'interfaccia implementata, quindi anche se fossero pubblici, non sono facilmente accessibili.
HDave

2

Preferisco i campi, ma mi sono imbattuto in una situazione che sembra costringermi a posizionare le annotazioni su getter.

Con l'implementazione di Hibernate JPA, @Embeddednon sembra funzionare sui campi. Quindi questo deve andare avanti. E una volta che lo metti sul getter, allora anche le varie @Columnannotazioni devono andare sui getter. (Penso che Hibernate non voglia mescolare campi e getter qui.) E una volta che stai mettendo @Columnsu getter in una classe, probabilmente ha senso farlo dappertutto.


2

Prediligo gli accessor sul campo. Il codice è molto più pulito. Tutte le annotazioni possono essere inserite in una sezione di una classe e il codice è molto più facile da leggere.

Ho riscontrato un altro problema con gli accessor delle proprietà: se nella tua classe sono presenti metodi getXYZ che NON sono annotati come associati a proprietà persistenti, l'ibernazione genera sql per tentare di ottenere tali proprietà, generando alcuni messaggi di errore molto confusi. Due ore sprecate. Non ho scritto questo codice; Ho sempre usato gli accessi sul campo in passato e non ho mai riscontrato questo problema.

Versioni di ibernazione utilizzate in questa app:

<!-- 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>

2

È necessario scegliere l'accesso tramite i campi rispetto all'accesso tramite le proprietà. Con i campi è possibile limitare i dati inviati e ricevuti. Con le proprietà via puoi inviare più dati come host e impostare le denominazioni G (che la fabbrica imposta la maggior parte delle proprietà in totale).




1

Abbiamo creato bean di entità e utilizzato annotazioni getter. Il problema che abbiamo riscontrato è questo: alcune entità hanno regole complesse per alcune proprietà riguardo a quando possono essere aggiornate. La soluzione era quella di avere una logica di business in ogni setter che determina se il valore effettivo è cambiato o meno e, in tal caso, se la modifica dovrebbe essere consentita. Naturalmente, Hibernate può sempre impostare le proprietà, quindi abbiamo finito con due gruppi di setter. Abbastanza brutto.

Leggendo i post precedenti, vedo anche che fare riferimento alle proprietà dall'interno dell'entità potrebbe causare problemi con le raccolte che non si caricano.

In conclusione, mi spingerei verso l'annotazione dei campi in futuro.


0

Normalmente i fagioli sono POJO, quindi hanno comunque degli accessori.

Quindi la domanda non è "quale è meglio?", Ma semplicemente "quando utilizzare l'accesso al campo?". E la risposta è "quando non hai bisogno di un setter / getter per il campo!".


4
Il problema è che non puoi mescolare l'accesso al campo e l'accesso alla proprietà in un POJO - devi sceglierne uno
Martin OConnor,

Veramente? Devo averlo dimenticato. Ad ogni modo, utilizzo sempre POJO e gli accessori.
Vladimir Dyuzhev,

Nota che con JPA 2.0 (che non esisteva quando è stata posta questa domanda) ora puoi mescolare i tipi di accesso usando l'annotazione @AccessType.
mtpettyp,

0

ci sto pensando e ho scelto il metodo accesor

perché?

perché field e methos accesses sono gli stessi ma se in seguito avrò bisogno di un po 'di logica nel campo di caricamento, salvo spostare tutte le annotazioni inserite nei campi

Saluti

Grubhart


0

Per rendere più pulite le tue classi, inserisci l'annotazione nel campo, quindi usa @Access (AccessType.PROPERTY)



0

AccessType.PROPERTY: L'implementazione della persistenza EJB caricherà lo stato nella classe tramite i metodi "setter" JavaBean e recupererà lo stato dalla classe utilizzando i metodi "getter" JavaBean. Questo è il valore predefinito.

AccessType.FIELD: lo stato viene caricato e recuperato direttamente dai campi della classe. Non è necessario scrivere "getter" e "setter" JavaBean.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.