Saya telah bekerja dengan JPA (implementasi Hibernate) untuk beberapa waktu sekarang dan setiap kali saya perlu membuat entitas saya menemukan diri saya berjuang dengan masalah sebagai AccessType, properti tidak berubah, sama dengan / kode hash, ....
Jadi saya memutuskan untuk mencoba dan menemukan praktik terbaik umum untuk setiap masalah dan menuliskannya untuk penggunaan pribadi.
Namun saya tidak keberatan bagi siapa pun untuk mengomentarinya atau mengatakan di mana saya salah.
Kelas Entitas
mengimplementasikan Serializable
Alasan: Spesifikasi mengatakan Anda harus melakukannya, tetapi beberapa penyedia JPA tidak menegakkan ini. Hibernate sebagai penyedia JPA tidak menegakkan ini, tetapi bisa gagal di suatu tempat jauh di dalam perutnya dengan ClassCastException, jika Serializable belum dilaksanakan.
Konstruktor
membuat konstruktor dengan semua bidang entitas yang diperlukan
Alasan: Seorang konstruktor harus selalu membiarkan instance dibuat dalam keadaan waras.
selain konstruktor ini: memiliki konstruktor default pribadi paket
Alasan: Konstruktor default diperlukan agar Hibernate menginisialisasi entitas; pribadi diperbolehkan tetapi paket privat (atau publik) diperlukan untuk pembuatan proxy runtime dan pengambilan data yang efisien tanpa instrumentasi bytecode.
Bidang / Properti
Gunakan akses lapangan secara umum dan akses properti saat dibutuhkan
Alasan: ini mungkin masalah yang paling bisa diperdebatkan karena tidak ada argumen yang jelas dan meyakinkan untuk satu atau yang lain (akses properti vs akses lapangan); Namun, akses bidang tampaknya menjadi favorit umum karena kode yang lebih jelas, enkapsulasi yang lebih baik dan tidak perlu membuat setter untuk bidang yang tidak dapat diubah
Abaikan setter untuk bidang yang tidak dapat diubah (tidak diperlukan untuk bidang tipe akses)
- properti mungkin bersifat pribadi
Alasan: Saya pernah mendengar bahwa dilindungi lebih baik untuk kinerja (Hibernate) tetapi yang dapat saya temukan di web adalah: Hibernate dapat mengakses metode publik, privat, dan terlindungi, serta bidang publik, swasta dan terlindungi secara langsung . Pilihannya terserah Anda dan Anda dapat mencocokkannya agar sesuai dengan desain aplikasi Anda.
Kode yang sama / hash
- Jangan pernah gunakan id yang dihasilkan jika id ini hanya disetel saat mempertahankan entitas
- Menurut preferensi: gunakan nilai yang tidak dapat diubah untuk membentuk Kunci Bisnis yang unik dan gunakan ini untuk menguji kesetaraan
- jika Kunci Bisnis unik tidak tersedia gunakan UUID non-transien yang dibuat ketika entitas diinisialisasi; Lihat artikel hebat ini untuk informasi lebih lanjut.
- tidak pernah merujuk ke entitas terkait (ManyToOne); jika entitas ini (seperti entitas induk) perlu menjadi bagian dari Kunci Bisnis, maka bandingkan ID saja. Memanggil getId () pada proxy tidak akan memicu pemuatan entitas, selama Anda menggunakan tipe akses properti .
Entitas Contoh
@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
}
Saran lain untuk ditambahkan ke daftar ini lebih dari diterima ...
MEMPERBARUI
Sejak membaca artikel ini saya telah mengadaptasi cara saya menerapkan eq / hC:
- jika kunci bisnis sederhana yang kekal tersedia: gunakan itu
- dalam semua kasus lain: gunakan uuid
final
(menilai oleh setingan Anda setter, saya kira Anda juga).
notNull
?