Ich arbeite seit einiger Zeit mit JPA (Implementation Hibernate) und jedes Mal, wenn ich Entitäten erstellen muss, habe ich Probleme mit AccessType, unveränderlichen Eigenschaften, equals / hashCode, ....
Deshalb habe ich mich entschlossen, die allgemeinen Best Practices für jede Ausgabe herauszufinden und diese für den persönlichen Gebrauch aufzuschreiben.
Es würde mir jedoch nichts ausmachen, wenn jemand dies kommentiert oder mir sagt, wo ich falsch liege.
Entitätsklasse
Serializable implementieren
Grund: Die Spezifikation besagt, dass Sie dies tun müssen, aber einige JPA-Anbieter erzwingen dies nicht. Der Ruhezustand als JPA-Anbieter erzwingt dies nicht, kann jedoch mit ClassCastException irgendwo tief im Magen fehlschlagen, wenn Serializable nicht implementiert wurde.
Konstruktoren
Erstellen Sie einen Konstruktor mit allen erforderlichen Feldern der Entität
Grund: Ein Konstruktor sollte die erstellte Instanz immer in einem vernünftigen Zustand belassen.
Neben diesem Konstruktor: Haben Sie ein Paket privaten Standardkonstruktor
Grund: Der Standardkonstruktor ist erforderlich, damit der Ruhezustand die Entität initialisiert. privat ist zulässig, aber für die Laufzeit-Proxy-Generierung und den effizienten Datenabruf ohne Bytecode-Instrumentierung ist eine private (oder öffentliche) Paketsichtbarkeit erforderlich.
Felder / Eigenschaften
Verwenden Sie den Feldzugriff im Allgemeinen und den Eigenschaftenzugriff bei Bedarf
Grund: Dies ist wahrscheinlich das umstrittenste Problem, da es für das eine oder andere keine klaren und überzeugenden Argumente gibt (Eigenschaftszugriff vs. Feldzugriff). Der Feldzugriff scheint jedoch allgemeiner Favorit zu sein, da der Code klarer ist, die Kapselung besser ist und keine Setter für unveränderliche Felder erstellt werden müssen
Setter für unveränderliche Felder weglassen (für Zugriffstypfeld nicht erforderlich)
- Eigenschaften können privat sein
Grund: Ich habe einmal gehört, dass geschützt besser für die Leistung im Ruhezustand ist, aber alles, was ich im Web finden kann, ist: Der Ruhezustand kann direkt auf öffentliche, private und geschützte Zugriffsmethoden sowie auf öffentliche, private und geschützte Felder zugreifen . Die Wahl liegt bei Ihnen und Sie können sie an Ihr Anwendungsdesign anpassen.
Gleich / hashCode
- Verwenden Sie niemals eine generierte ID, wenn diese ID nur festgelegt wird, wenn die Entität beibehalten wird
- Nach Präferenz: Verwenden Sie unveränderliche Werte, um einen eindeutigen Geschäftsschlüssel zu bilden, und testen Sie damit die Gleichheit
- Wenn kein eindeutiger Geschäftsschlüssel verfügbar ist, verwenden Sie eine nicht vorübergehende UUID, die bei der Initialisierung der Entität erstellt wird. Weitere Informationen finden Sie in diesem großartigen Artikel .
- Verweisen Sie niemals auf verwandte Entitäten (ManyToOne). Wenn diese Entität (wie eine übergeordnete Entität) Teil des Geschäftsschlüssels sein muss, vergleichen Sie nur die IDs. Das Aufrufen von getId () auf einem Proxy löst das Laden der Entität nicht aus, solange Sie den Eigenschaftszugriffstyp verwenden .
Beispiel Entität
@Entity
@Table(name = "ROOM")
public class Room implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "room_id")
private Integer id;
@Column(name = "number")
private String number; //immutable
@Column(name = "capacity")
private Integer capacity;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "building_id")
private Building building; //immutable
Room() {
// default constructor
}
public Room(Building building, String number) {
// constructor with required field
notNull(building, "Method called with null parameter (application)");
notNull(number, "Method called with null parameter (name)");
this.building = building;
this.number = number;
}
@Override
public boolean equals(final Object otherObj) {
if ((otherObj == null) || !(otherObj instanceof Room)) {
return false;
}
// a room can be uniquely identified by it's number and the building it belongs to; normally I would use a UUID in any case but this is just to illustrate the usage of getId()
final Room other = (Room) otherObj;
return new EqualsBuilder().append(getNumber(), other.getNumber())
.append(getBuilding().getId(), other.getBuilding().getId())
.isEquals();
//this assumes that Building.id is annotated with @Access(value = AccessType.PROPERTY)
}
public Building getBuilding() {
return building;
}
public Integer getId() {
return id;
}
public String getNumber() {
return number;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(getNumber()).append(getBuilding().getId()).toHashCode();
}
public void setCapacity(Integer capacity) {
this.capacity = capacity;
}
//no setters for number, building nor id
}
Andere Vorschläge, die dieser Liste hinzugefügt werden sollen, sind mehr als willkommen ...
AKTUALISIEREN
Seit ich diesen Artikel gelesen habe, habe ich meine Art der Implementierung von eq / hC angepasst:
- Wenn ein unveränderlicher einfacher Geschäftsschlüssel verfügbar ist: Verwenden Sie diesen
- in allen anderen fällen: benutze eine uuid
final
(gemessen an Ihrer Auslassung von Setzern würde ich vermuten, dass Sie dies auch tun).
notNull
das?