Anmerkungen zum Ruhezustand - Was ist besser, Feld- oder Eigenschaftenzugriff?

Antworten:

33

Ich bevorzuge Accessoren, da ich meinen Accessoren jederzeit eine Geschäftslogik hinzufügen kann. Hier ist ein Beispiel:

@Entity
public class Person {

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

Wenn Sie andere Bibliotheken in den Mix einfügen (z. B. eine JSON-konvertierende Bibliothek oder BeanMapper oder Dozer oder eine andere Bean-Mapping- / Klon-Bibliothek basierend auf Getter / Setter-Eigenschaften), haben Sie außerdem die Garantie, dass die Bibliothek mit der Persistenz synchronisiert ist Manager (beide verwenden den Getter / Setter).

Miguel Ping
quelle
17
Beachten Sie, dass es hier darum geht, wie der ORM auf Ihre Felder / Eigenschaften zugreift und nicht auf Ihren Anwendungscode. Mit Feldzugriff würde Ihre Methode getNickName () genau so funktionieren, wie Sie es erwarten würden. Das Gleiche gilt nicht, wenn Sie die persistenten 'Eigenschaften' außerhalb von Getter / Setter verwenden. Hier können Probleme mit dem Zugriff auf Eigenschaften und dem verzögerten Laden auftreten. Also nein, ich stimme diesem Argument im Allgemeinen nicht zu. Als ich das letzte Mal Hibernate überprüfte, gab es jedoch Probleme mit dem Feldzugriff auf @ ID-Felder.
Rob Bygrave
11
Diese Antwort bezieht sich nicht auf die Frage. Beste Antwort s von Duffymo
Janning
9
In Accessoren sollte keine Geschäftslogik vorhanden sein. Das ist kein offensichtliches Verhalten.
Iuriisusuk
Warum ist diese Antwortmarke richtig? Es ist nicht wahr, dass Sie ein Feld zuordnen und es auf die gleiche Weise als Setter / Getter bereitstellen können.
Lucke
246

Es gibt Argumente für beide, aber die meisten von ihnen stammen aus bestimmten Benutzeranforderungen "Was ist, wenn Sie Logik hinzufügen müssen für" oder "xxxx unterbricht die Kapselung". Allerdings hat niemand die Theorie wirklich kommentiert und ein richtig begründetes Argument vorgebracht.

Was macht Hibernate / JPA tatsächlich, wenn es ein Objekt beibehält? Nun, es behält den STATE des Objekts bei. Das bedeutet, dass es so gespeichert wird, dass es leicht reproduziert werden kann.

Was ist Kapselung? Kapselung bedeutet, die Daten (oder den Status) mit einer Schnittstelle zu kapseln, über die die Anwendung / der Client sicher auf die Daten zugreifen kann, um sie konsistent und gültig zu halten.

Stellen Sie sich das wie MS Word vor. MS Word verwaltet ein Modell des Dokuments im Speicher - die Dokumente STATE. Es bietet eine Benutzeroberfläche, über die der Benutzer das Dokument ändern kann - eine Reihe von Schaltflächen, Werkzeugen, Tastaturbefehlen usw. Wenn Sie dieses Dokument jedoch beibehalten (speichern), wird der interne Status gespeichert, nicht der Satz von Tastendrücken und Mausklicks zum Generieren.

Durch das Speichern des internen Status des Objekts wird die Kapselung NICHT unterbrochen. Andernfalls verstehen Sie nicht wirklich, was Kapselung bedeutet und warum sie vorhanden ist. Es ist wirklich wie bei der Objektserialisierung.

Aus diesem Grund ist es in den meisten Fällen angebracht, die FELDER und nicht die ZUGRIFFE beizubehalten. Dies bedeutet, dass ein Objekt genau so aus der Datenbank wiederhergestellt werden kann, wie es gespeichert wurde. Es sollte keine Validierung erforderlich sein, da dies auf dem Original durchgeführt wurde, als es erstellt wurde und bevor es in der Datenbank gespeichert wurde (es sei denn, Gott bewahre, Sie speichern ungültige Daten in der Datenbank !!!!). Ebenso sollte es nicht erforderlich sein, Werte zu berechnen, da diese bereits vor dem Speichern des Objekts berechnet wurden. Das Objekt sollte genauso aussehen wie vor dem Speichern. In der Tat erhöhen Sie durch Hinzufügen zusätzlicher Elemente zu den Gettern / Setzern das Risiko, dass Sie etwas neu erstellen, das keine exakte Kopie des Originals ist.

Natürlich wurde diese Funktionalität aus einem bestimmten Grund hinzugefügt. Es kann einige gültige Anwendungsfälle für das Fortbestehen der Accessoren geben, diese sind jedoch normalerweise selten. Ein Beispiel könnte sein, dass Sie vermeiden möchten, einen berechneten Wert beizubehalten, obwohl Sie möglicherweise die Frage stellen möchten, warum Sie ihn nicht bei Bedarf im Getter des Werts berechnen oder ihn im Getter träge initialisieren. Persönlich kann ich mir keinen guten Anwendungsfall vorstellen, und keine der Antworten hier gibt wirklich eine "Software Engineering" -Antwort.

Martin
quelle
9
Die Antwort der Softwareentwicklung lautet: Die Verwendung von Accessoren verstößt gegen DRY.
Sourcedelica
1
@ Martin Ich habe eine Folgefrage zum letzten Absatz Ihrer Antwort. Sie haben geschrieben "Ein Beispiel könnte sein, dass Sie vermeiden möchten, einen berechneten Wert beizubehalten". Wie können Sie vermeiden, einen berechneten Wert beizubehalten, indem Sie auf Eigenschaften zugreifen? Ich weiß, dass Sie argumentieren, dies nicht zu tun, aber ich verstehe den Punkt hier nicht. Kannst du bitte Erklären?
Geek
4
@Geek Jetzt, wo ich es zurückgelesen habe, bin ich mir selbst nicht ganz sicher. Es ist zwei Jahre her, seit ich diese Antwort geschrieben habe. Ich denke, ein besseres Beispiel könnte sein, wenn Sie mit einer Legacy-Datenbank arbeiten und die Daten anders dargestellt werden als Ihr Objektmodell - Accessoren könnten eine Zuordnung zwischen beiden bereitstellen.
Martin
23
Ein guter Anwendungsfall für die Zuordnung von Accessoren ist das Hinzufügen von Zuordnungsinformationen zu Unterklassen von Entitätsklassen von Drittanbietern, die nicht an eine Persistenzimplementierung gebunden sind. Da Felder in diesen Klassen privat sind, müssen Sie Accessoren überschreiben und ihnen Zuordnungsanmerkungen hinzufügen. Eine andere Möglichkeit wäre die Verwendung der XML-Zuordnung, aber einige Dinge sind dort sehr schwer zu tun. Wenn Sie also Anmerkungen wünschen und Klassen von Drittanbietern zuordnen möchten, müssen Sie diese unterordnen und Anmerkungen zu Accessoren hinzufügen.
Elnur Abdurrakhimov
5
@ ElnurAbdurrakhimov los geht's, ein hervorragendes Beispiel. Vielen Dank.
Martin
79

Ich bevorzuge den Feldzugriff, da ich auf diese Weise nicht gezwungen bin, für jede Eigenschaft Getter / Setter bereitzustellen.

Eine schnelle Umfrage über Google zeigt, dass der Feldzugriff die Mehrheit ist (z . B. http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype ).

Ich glaube, dass der Feldzugriff die von Spring empfohlene Redewendung ist, aber ich kann keinen Hinweis finden, um dies zu belegen.

Es gibt eine verwandte SO-Frage , die versucht hat, die Leistung zu messen, und zu dem Schluss gekommen ist, dass es "keinen Unterschied" gibt.

Duffymo
quelle
Wenn Sie Setter Getter nicht in Entity bereitstellen, was ist dann die Verwendung dieses Feldes ... Sie können es nirgendwo in der Anwendung verwenden, da Felder privat sind
anshulkatta
1
Ist es nicht immer richtig, einen Getter und Setter für Ihre Felder bereitzustellen? Ich denke, mein Kommentar hier ist nicht immer richtig, da ich ein öffentliches Feld angenommen habe, während es offensichtlich ein privates Feld sein könnte, auf das niemals zugegriffen wird.
Mathijs Segers
3
@anshulkatta Ich denke, ich sollte Ihre Fragen wirklich beantworten, denn darum geht es bei der Kapselung. Im Idealfall sollten alle Ihre Felder privat sein, und wenn möglich sollten sie keine Getter oder Setter haben - das ist die beste Kapselungsstufe, auf die Sie hoffen können. Betrachten Sie eine Passwortprüfung. 2 private Felder passwordHash und failedAttempts. Beide können ohne Getter oder Setter privat sein. Sie werden von bool checkPassword (String-Passwort) verwendet, das hasht, gegen passwordHash prüft und dann failedAttempt aktualisiert und ein Ergebnis zurückgibt. Es ist kein anderer Code erforderlich, um jemals auf diese beiden Felder zuzugreifen.
Martin
2
@anshulkatta Es sollte beachtet werden, dass Getter und Setter in OOP ein Anti-Pattern sind, sie stammen aus der prozeduralen Programmierung, eine Klasse mit ihnen bricht das Kapselungsprinzip und generiert viel Boilerplate-Code, das heißt die gleiche Art von Code immer und immer wieder wiederholt. Objekte sollten unveränderlich sein. Wenn eine Änderung ihrer Eigenschaften erforderlich ist, sollte dies durch eine Methode erfolgen, die mehr als nur den Wert der Eigenschaft zurückgibt.
Uriel Arvizu
Nicht so. "Anti-Pattern" ist in diesem Fall Ansichtssache, kein Dogma. Trotzdem wird der Feldzugriff immer noch bevorzugt. Eine bessere Idee ist es, ORM-Lösungen insgesamt zu scheuen. Erfahren Sie, wie Sie richtiges SQL schreiben.
Duffymo
38

Hier ist eine Situation, in der Sie Eigenschaften-Accessoren verwenden MÜSSEN. Stellen Sie sich vor, Sie haben eine GENERIC abstrakte Klasse mit viel Implementierungsgüte, die Sie in 8 konkrete Unterklassen erben können:

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
 }

Wie genau sollten Sie diese Klasse kommentieren? Die Antwort lautet: SIE KÖNNEN es weder mit Feld- noch mit Eigenschaftszugriff kommentieren, da Sie die Zielentität zu diesem Zeitpunkt nicht angeben können. Sie MÜSSEN die konkreten Implementierungen mit Anmerkungen versehen. Da die persistierten Eigenschaften in dieser Oberklasse deklariert sind, MÜSSEN Sie den Eigenschaftszugriff in den Unterklassen verwenden.

Feldzugriff ist in einer Anwendung mit abstrakten generischen Superklassen keine Option.

HDave
quelle
2
touche. Daran hatte ich nicht gedacht. Ich wette, Hibernate wirft ein paar verrückte SQL für diese raus.
Joseph Lust
8
Dieses Problem klingt mechanisch schwierig zu lösen, ohne Eigenschaften zu kommentieren, aber ich bin nie auf einen Fall gestoßen, in dem ich eine abstrakte generische Klasse mit viel Implementierung benötigte, die ich auch beibehalten wollte. Normalerweise erstelle ich eine Klassenhierarchie, um mein Objekt polymorph zu machen (was es zu generischen Unterbrechungen macht) und nicht nur für die Wiederverwendung von Code. Und "viele, viele Implementierungen" verstoßen ohnehin oft gegen SRP. In diesem Fall würde ich es wahrscheinlich in separate Klassen verschieben. Gibt es ein konkretes Beispiel, das diesen Anwendungsfall offensichtlicher macht?
Merlyn Morgan-Graham
Das einzige konkrete Beispiel, das ich habe, ist meine Anwendung, die ich nicht in einem Kommentar mit 500 Zeichen beschreiben kann
;-)
3
Sie können den Feldzugriff abstract T getOneThing()und abstract void setOneThing(T thing)und verwenden.
Arturo Volpe
33

Ich bevorzuge und benutze Property Accessors:

  • Ich kann Logik hinzufügen, wenn es nötig ist (wie in der akzeptierten Antwort erwähnt).
  • Damit kann ich anrufen, foo.getId() ohne einen Proxy zu initialisieren (wichtig bei Verwendung von Hibernate, bis HHH-3718 aufgelöst ist).

Nachteil:

  • Dadurch ist der Code weniger lesbar. Sie müssen beispielsweise eine ganze Klasse durchsuchen, um festzustellen, ob sich dort Code @Transientbefindet.
Pascal Thivent
quelle
Wenn Sie jedoch einen JPA-Anbieter verwenden, der keine "Proxies" hat, haben Sie dieses Problem nicht, auch bekannt als "Ihr JPA-Anbieter legt Ihnen auf".
Neil Stockton
13

Das hängt wirklich von einem bestimmten Fall ab - beide Optionen sind aus einem bestimmten Grund verfügbar. IMO läuft es auf drei Fälle hinaus:

  1. Setter hat eine Logik, die zum Zeitpunkt des Ladens einer Instanz aus einer Datenbank nicht ausgeführt werden sollte. Beispielsweise findet im Setter eine gewisse Wertüberprüfung statt. Die von db stammenden Daten sollten jedoch gültig sein (andernfalls würden sie nicht dort ankommen (:); in diesem Fall ist der Feldzugriff am besten geeignet.
  2. Setter hat eine Logik, die auch beim Laden einer Instanz aus db immer aufgerufen werden sollte. Beispielsweise wird die zu initialisierende Eigenschaft zur Berechnung eines berechneten Feldes verwendet (z. B. Eigenschaft - ein Geldbetrag, berechnete Eigenschaft - insgesamt mehrere monetäre Eigenschaften derselben Instanz); In diesem Fall ist ein Zugriff auf das Eigentum erforderlich.
  3. Keiner der oben genannten Fälle - dann sind beide Optionen anwendbar. Bleiben Sie einfach konsistent (z. B. wenn in dieser Situation der Feldzugriff die Wahl ist, verwenden Sie ihn in einer ähnlichen Situation ständig).
01es
quelle
Ich bin neu im Ruhezustand und habe mit der gleichen Frage zu kämpfen. Ich denke, dieser Beitrag liefert die klarste Antwort. Danke dir.
Sam Levin
12

Ich würde den Feldzugriff und NICHT Anmerkungen zu den Gettern (Eigenschaftszugriff) dringend empfehlen, wenn Sie in den Setzern mehr tun möchten, als nur den Wert festzulegen (z. B. Verschlüsselung oder Berechnung).

Das Problem beim Eigenschaftszugriff besteht darin, dass die Setter auch beim Laden des Objekts aufgerufen werden. Dies hat für mich viele Monate lang gut funktioniert, bis wir die Verschlüsselung einführen wollten. In unserem Anwendungsfall wollten wir ein Feld im Setter verschlüsseln und im Getter entschlüsseln. Das Problem beim Zugriff auf Eigenschaften bestand nun darin, dass Hibernate beim Laden des Objekts auch den Setter aufrief, um das Feld zu füllen, und somit den verschlüsselten Wert erneut verschlüsselte. In diesem Beitrag wird auch Folgendes erwähnt: Java Hibernate: Unterschiedliches Verhalten der Eigenschaftssatzfunktion, je nachdem, wer es aufruft

Dies hat mir Kopfschmerzen bereitet, bis ich mich an den Unterschied zwischen Feldzugriff und Eigenschaftszugriff erinnerte. Jetzt habe ich alle meine Anmerkungen vom Eigenschaftszugriff zum Feldzugriff verschoben und es funktioniert jetzt einwandfrei.

Christoph
quelle
Ja - Ich habe festgestellt, dass Sie bei Verwendung des Eigenschaftszugriffs in Ihrem Setter nur den Feldwert festlegen können.
HDave
2
+1 Von Gettern / Setzern fernhalten. Ich benutze projectlombok.org und halte sie vor Entwicklern verborgen.
Bhantol
11

Ich bevorzuge die Verwendung des Feldzugriffs aus folgenden Gründen:

  1. Der Eigenschaftszugriff kann zu sehr schlimmen Fehlern führen, wenn equals / hashCode implementiert und Felder direkt referenziert werden (im Gegensatz zu ihren Gettern). Dies liegt daran, dass der Proxy nur initialisiert wird, wenn auf die Getter zugegriffen wird, und ein Direktfeldzugriff einfach null zurückgeben würde.

  2. Für den Eigenschaftszugriff müssen Sie alle Dienstprogrammmethoden (z. B. addChild / removeChild) als mit Anmerkungen versehen @Transient.

  3. Mit dem Feldzugriff können wir das @ Versionsfeld ausblenden, indem wir überhaupt keinen Getter verfügbar machen. Ein Getter kann auch dazu führen, dass ein Setter hinzugefügt wird, und das versionFeld sollte niemals manuell eingestellt werden (was zu sehr unangenehmen Problemen führen kann). Alle Versionsinkrementierungen sollten durch explizites Sperren von OPTIMISTIC_FORCE_INCREMENT oder PESSIMISTIC_FORCE_INCREMENT ausgelöst werden .

Vlad Mihalcea
quelle
1. Wie verhindert die Feldzugriffsstrategie dies? Dies scheint eine allgemeine Gefahr für Proxys zu sein, unabhängig vom Zugriffsstil. 2. Sind Sie sicher, dass es nur Utility Getter sein sollten? (aber trotzdem ein gutes Argument). 3. Das Bereitstellen von Accessoren für versionFelder ist häufig in Situationen nützlich, in denen DTOs anstelle von getrennten Entitäten verwendet werden.
Dragan Bozanovic
1. Aufgrund dessen, wann ein Proxy initialisiert wird. 2. 100% sicher. 3. Das ist ein gültiger Punkt.
Vlad Mihalcea
Verzeihen Sie meine Unwissenheit und den möglichen Mangel an Textinterpretation (ich bin kein englischer Muttersprachler). Nur um zu verdeutlichen, ist der Feldzugriff, wenn keine Getter / Setter-Methoden benötigt werden. Für ein POJO, das ganzheitlich verwendet wird, sind die Felder also öffentlich? Aber Sie sagen etwas im ersten Thema und der verlinkte Blog-Beitrag sagt das Gegenteil. Was ich verstanden habe war, dass Sie bei der Verwendung von Proxys und Feldzugriff keine Gleichheit verwenden können.
MaikoID
Nein. Feldzugriff bedeutet, dass der Ruhezustand die Felder über Reflexionen verwendet, um Entitätsattribute zu lesen. Weitere Informationen finden Sie im Abschnitt Zugriffstyp im Hibernate-Benutzerhandbuch .
Vlad Mihalcea
7

Ich denke, das Annotieren der Eigenschaft ist besser, da das Aktualisieren von Feldern die Kapselung direkt unterbricht, selbst wenn Ihr ORM dies tut.

Hier ist ein großartiges Beispiel dafür, wo es Sie verbrennen wird: Sie möchten wahrscheinlich, dass sich Ihre Anmerkungen für den Validator und die Persistenz im Ruhezustand an derselben Stelle befinden (entweder Felder oder Eigenschaften). Wenn Sie Ihre Validatoren im Ruhezustand testen möchten, die in einem Feld mit Anmerkungen versehen sind, können Sie keinen Mock Ihrer Entität verwenden, um Ihren Komponententest nur auf den Validator zu isolieren. Autsch.

Justin Standard
quelle
2
Aus diesem Grund setzen Sie Validator-Annotationen auf Accessoren und Persistenz-Annotationen auf Feldern
Fishbone
6

Ich glaube, dass der Zugriff auf Immobilien im Vergleich zum Zugriff auf Felder in Bezug auf die verzögerte Initialisierung geringfügig unterschiedlich ist.

Betrachten Sie die folgenden Zuordnungen für 2 grundlegende Bohnen:

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

Und die folgenden Unit-Tests:

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

Sie werden den subtilen Unterschied in den erforderlichen Auswahlen sehen:

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

Das heißt, für das Anrufen ist fb.getId()eine Auswahl erforderlich , für das Aufrufen pb.getId()jedoch nicht.

Toolkit
quelle
Das ist lustig! :) Aber es ist ein implementierungsspezifisches Verhalten, da bin ich mir sicher. I
Vladimir Dyuzhev
Ja, ich denke, das liegt daran, dass nur die persistenten Klassen instrumentiert sind. Es ist jedoch schade, weil das ID-Feld oft das einzige Feld ist, das keinen geschäftlichen Wert hat und keinen Accessor benötigt.
Maurice Perry
6

Lassen Sie mich versuchen, die wichtigsten Gründe für die Wahl des feldbasierten Zugriffs zusammenzufassen. Wenn Sie tiefer eintauchen möchten, lesen Sie bitte diesen Artikel in meinem Blog: Zugriffsstrategien in JPA und Hibernate - Was ist besser, Feld- oder Immobilienzugriff?

Feldbasierter Zugriff ist bei weitem die bessere Option. Hier sind 5 Gründe dafür:

Grund 1: Bessere Lesbarkeit Ihres Codes

Wenn Sie den feldbasierten Zugriff verwenden, versehen Sie Ihre Entitätsattribute mit Ihren Zuordnungsanmerkungen. Wenn Sie die Definition aller Entitätsattribute ganz oben in Ihrer Klasse platzieren, erhalten Sie eine relativ kompakte Ansicht aller Attribute und ihrer Zuordnungen.

Grund 2: Lassen Sie Getter- oder Setter-Methoden weg, die von Ihrer Anwendung nicht aufgerufen werden sollten

Ein weiterer Vorteil des feldbasierten Zugriffs besteht darin, dass Ihr Persistenzanbieter, z. B. Hibernate oder EclipseLink, die Getter- und Setter-Methoden Ihrer Entitätsattribute nicht verwendet. Das bedeutet, dass Sie keine Methode angeben müssen, die von Ihrem Geschäftscode nicht verwendet werden sollte. Dies ist am häufigsten bei Setter-Methoden für generierte Primärschlüsselattribute oder Versionsspalten der Fall . Ihr Persistenzanbieter verwaltet die Werte dieser Attribute, und Sie sollten sie nicht programmgesteuert festlegen.

Grund 3: Flexible Implementierung von Getter- und Setter-Methoden

Da Ihr Persistenzanbieter die Getter- und Setter-Methoden nicht aufruft, sind sie nicht gezwungen, externe Anforderungen zu erfüllen. Sie können diese Methoden beliebig implementieren. Auf diese Weise können Sie geschäftsspezifische Validierungsregeln implementieren, zusätzliche Geschäftslogik auslösen oder das Entitätsattribut in einen anderen Datentyp konvertieren.

Sie können dies beispielsweise verwenden, um eine optionale Zuordnung oder ein Attribut in Java zu verpacken Optional.

Grund 4: Dienstprogrammmethoden müssen nicht als markiert werden @Transient

Ein weiterer Vorteil der feldbasierten Zugriffsstrategie besteht darin, dass Sie Ihre Dienstprogrammmethoden nicht mit Anmerkungen versehen müssen @Transient. Diese Anmerkung teilt Ihrem Persistenzanbieter mit, dass eine Methode oder ein Attribut nicht Teil des persistenten Status der Entität ist. Und da beim Zugriff vom Feldtyp der persistente Status durch die Attribute Ihrer Entität definiert wird, ignoriert Ihre JPA-Implementierung alle Methoden Ihrer Entität.

Grund 5: Vermeiden Sie Fehler bei der Arbeit mit Proxys

Hibernate verwendet Proxys für das langsame Abrufen von Zuordnungen, sodass die Initialisierung dieser Zuordnungen gesteuert werden kann. Dieser Ansatz funktioniert in fast allen Situationen einwandfrei. Es führt jedoch zu einer gefährlichen Gefahr, wenn Sie den eigenschaftsbasierten Zugriff verwenden.

Wenn Sie den eigenschaftsbasierten Zugriff verwenden, initialisiert Hibernate die Attribute des Proxy-Objekts, wenn Sie die Getter-Methode aufrufen. Dies ist immer dann der Fall, wenn Sie das Proxy-Objekt in Ihrem Geschäftscode verwenden. Viele Gleichheits- und HashCode-Implementierungen greifen jedoch direkt auf die Attribute zu. Wenn Sie zum ersten Mal auf eines der Proxy-Attribute zugreifen, sind diese Attribute immer noch nicht initialisiert.

Thorben Janssen
quelle
3

Standardmäßig greifen JPA-Anbieter auf die Werte von Entitätsfeldern zu und ordnen diese Felder Datenbankspalten mit den Methoden JavaBean Property Accessor (Getter) und Mutator (Setter) der Entität zu. Daher spielen die Namen und Typen der privaten Felder in einer Entität für JPA keine Rolle. Stattdessen betrachtet JPA nur die Namen und Rückgabetypen der JavaBean-Eigenschaftszugriffsberechtigten. Sie können dies mithilfe der @javax.persistence.AccessAnmerkung ändern, mit der Sie die Zugriffsmethode, die der JPA-Anbieter verwenden soll, explizit angeben können.

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

Die verfügbaren Optionen für die AccessType-Enumeration sind PROPERTY (Standardeinstellung) und FIELD. Mit PROPERTY ruft der Anbieter Feldwerte mithilfe der JavaBean-Eigenschaftsmethoden ab und legt diese fest. Mit FIELD kann der Anbieter Feldwerte mithilfe der Instanzfelder abrufen und festlegen. Als bewährte Methode sollten Sie sich nur an die Standardeinstellungen halten und JavaBean-Eigenschaften verwenden, sofern Sie keinen zwingenden Grund haben, etwas anderes zu tun.

Sie können diese Eigenschaftsanmerkungen entweder in die privaten Felder oder in die öffentlichen Zugriffsmethoden einfügen. Wenn Sie AccessType.PROPERTYdie privaten Felder anstelle der JavaBean-Accessoren verwenden (Standard) und mit Anmerkungen versehen, müssen die Feldnamen mit den JavaBean-Eigenschaftsnamen übereinstimmen. Die Namen müssen jedoch nicht übereinstimmen, wenn Sie die JavaBean-Accessoren mit Anmerkungen versehen. Wenn Sie AccessType.FIELDdie JavaBean-Accessoren anstelle der Felder verwenden und mit Anmerkungen versehen, müssen die Feldnamen ebenfalls mit den JavaBean-Eigenschaftsnamen übereinstimmen. In diesem Fall müssen sie nicht übereinstimmen, wenn Sie die Felder mit Anmerkungen versehen. Es ist am besten, nur konsistent zu sein und die JavaBean-Accessoren für AccessType.PROPERTYund die Felder für mit Anmerkungen zu versehen AccessType.FIELD.

Es ist wichtig, dass Sie niemals JPA-Eigenschaftsanmerkungen und JPA-Feldanmerkungen in derselben Entität mischen. Dies führt zu nicht angegebenem Verhalten und führt sehr wahrscheinlich zu Fehlern.

Faraz
quelle
2

Sind wir schon da

Das ist eine alte Präsentation, aber Rod schlägt vor, dass Anmerkungen zum Zugriff auf Eigenschaften anämische Domänenmodelle fördern und nicht die "Standard" -Methode für Anmerkungen sein sollten.

Manuel Palacio
quelle
2

Ein weiterer Punkt für den Feldzugriff ist, dass Sie andernfalls auch Setter für Sammlungen verfügbar machen müssen, was für mich eine schlechte Idee ist, da das Ändern der persistenten Sammlungsinstanz in ein Objekt, das nicht von Hibernate verwaltet wird, Ihre Datenkonsistenz definitiv beeinträchtigt.

Daher bevorzuge ich es, Sammlungen als geschützte Felder zu initialisieren, um Implementierungen im Standardkonstruktor zu leeren und nur deren Getter verfügbar zu machen. Dann wird nur verwaltete Operationen wie clear(), remove(), removeAll()usw. sind möglich, die nie Hibernate von Änderungen nicht bewusst machen.

Jiří Vypědřík
quelle
Sie sind nicht gezwungen, etwas freizulegen, da die Setter geschützt werden können. Außerdem sind diese Setter nicht Teil der zu implementierenden Schnittstelle. Selbst wenn sie öffentlich waren, sind sie nicht leicht zugänglich.
HDave
2

Ich bevorzuge Felder, aber ich bin auf eine Situation gestoßen, die mich zu zwingen scheint, die Anmerkungen auf Getter zu setzen.

Mit der Hibernate JPA-Implementierung @Embeddedscheint es nicht auf Feldern zu funktionieren. Das muss also auf den Punkt gebracht werden. Und sobald Sie das auf den Getter setzen, müssen die verschiedenen @ColumnAnmerkungen auch auf den Getter gehen. (Ich denke, Hibernate möchte hier keine Felder und Getter mischen.) Und wenn Sie einmal @ColumnGetter in einer Klasse angelegt haben, ist es wahrscheinlich sinnvoll, dies durchgehend zu tun.


quelle
2

Ich bevorzuge Feldzugänge. Der Code ist viel sauberer. Alle Anmerkungen können in einem Abschnitt einer Klasse platziert werden, und der Code ist viel einfacher zu lesen.

Ich habe ein weiteres Problem mit Eigenschaftenzugriffern festgestellt: Wenn Ihre Klasse getXYZ-Methoden enthält, die NICHT als mit persistenten Eigenschaften verknüpft gekennzeichnet sind, generiert der Ruhezustand SQL, um zu versuchen, diese Eigenschaften abzurufen, was zu einigen sehr verwirrenden Fehlermeldungen führt. Zwei Stunden verschwendet. Ich habe diesen Code nicht geschrieben. Ich habe in der Vergangenheit immer Feldzugriffe verwendet und bin nie auf dieses Problem gestoßen.

In dieser App verwendete Versionen für den Ruhezustand:

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

Sie sollten den Zugriff über Felder dem Zugriff über Eigenschaften vorziehen. Mit Feldern können Sie die gesendeten und empfangenen Daten begrenzen. Mit via-Eigenschaften können Sie mehr Daten als Host senden und G-Nennwerte festlegen (die werkseitig die meisten Eigenschaften insgesamt festlegen).

user10801787
quelle
1

Ich hatte die gleiche Frage bezüglich des Zugangstyps im Ruhezustand und fand hier einige Antworten .

Sundary
quelle
1

Wir haben Entity Beans erstellt und Getter-Annotationen verwendet. Das Problem, auf das wir gestoßen sind, ist folgendes: Einige Entitäten haben komplexe Regeln für einige Eigenschaften, wann sie aktualisiert werden können. Die Lösung bestand darin, in jedem Setter eine Geschäftslogik zu haben, die bestimmt, ob sich der tatsächliche Wert geändert hat oder nicht, und wenn ja, ob die Änderung zulässig sein sollte. Natürlich kann Hibernate die Eigenschaften immer festlegen, sodass wir zwei Gruppen von Setzern hatten. Ziemlich hässlich.

Beim Lesen früherer Beiträge sehe ich auch, dass das Verweisen auf die Eigenschaften innerhalb der Entität zu Problemen mit nicht geladenen Sammlungen führen kann.

Unterm Strich würde ich mich in Zukunft dazu neigen, die Felder mit Anmerkungen zu versehen.

Steve11235
quelle
0

Normalerweise sind Bohnen POJO, also haben sie sowieso Accessoren.

Die Frage lautet also nicht "Welches ist besser?", Sondern einfach "Wann soll der Feldzugriff verwendet werden?". Und die Antwort lautet "wenn Sie keinen Setter / Getter für das Feld brauchen!".

Vladimir Dyuzhev
quelle
4
Problem ist, dass Sie
Feldzugriff
"Ja wirklich?" Ich muss es vergessen haben. Jedenfalls benutze ich immer POJO und Accessoren.
Vladimir Dyuzhev
Beachten Sie, dass Sie mit JPA 2.0 (das zum Zeitpunkt der Beantwortung dieser Frage nicht verfügbar war) jetzt Zugriffstypen mithilfe der Annotation @AccessType mischen können.
Mtpettyp
0

Ich denke darüber nach und wähle die Methode accesor

Warum?

Da Feld- und Methos-Zugriff identisch sind, aber wenn ich später eine Logik im Ladefeld benötige, speichere ich das Verschieben aller in Feldern platzierten Anmerkungen

Grüße

Grubhart

user261548
quelle
0

Um Ihre Klassen übersichtlicher zu gestalten, geben Sie die Anmerkung in das Feld ein und verwenden Sie @Access (AccessType.PROPERTY).

ely
quelle
0

AccessType.PROPERTY: Die EJB-Persistenzimplementierung lädt den Status über JavaBean-Setter-Methoden in Ihre Klasse und ruft den Status mit JavaBean-Getter-Methoden aus Ihrer Klasse ab. Dies ist die Standardeinstellung.

AccessType.FIELD: Der Status wird direkt aus den Feldern Ihrer Klasse geladen und abgerufen. Sie müssen keine JavaBean "Getter" und "Setter" schreiben.

Daria Yu
quelle