ฉันได้ทำงานกับ JPA (Implementation Hibernate) มาระยะหนึ่งและทุกครั้งที่ฉันต้องสร้างเอนทิตีฉันพบว่าตัวเองกำลังดิ้นรนกับปัญหาเช่น AccessType, คุณสมบัติที่ไม่เปลี่ยนรูปแบบ, เท่ากับ / hashCode, ...
ดังนั้นฉันจึงตัดสินใจลองและหาแนวทางปฏิบัติที่ดีที่สุดโดยทั่วไปสำหรับแต่ละประเด็นแล้วจดบันทึกนี้ไว้ใช้ส่วนตัว
ฉันจะไม่รังเกียจอย่างไรก็ตามสำหรับทุกคนที่จะแสดงความคิดเห็นหรือบอกฉันว่าฉันผิด
คลาสเอนทิตี
ใช้ Serializable
เหตุผล: ข้อกำหนดระบุว่าคุณต้องทำ แต่ผู้ให้บริการ JPA บางรายไม่บังคับใช้ Hibernate ในฐานะผู้ให้บริการ JPA ไม่ได้บังคับใช้สิ่งนี้ แต่สามารถล้มเหลวได้บางส่วนในท้องของมันด้วย ClassCastException หาก Serializable ไม่ได้ถูกนำมาใช้
ก่อสร้าง
สร้างตัวสร้างที่มีฟิลด์ที่จำเป็นทั้งหมดของเอนทิตี
เหตุผล: คอนสตรัคควรปล่อยให้อินสแตนซ์ที่สร้างในสถานะที่มีเหตุผล
นอกเหนือจากตัวสร้างนี้: มีตัวสร้างค่าเริ่มต้นส่วนตัวของแพคเกจ
เหตุผล: ตัวสร้างเริ่มต้นจะต้องมีการไฮเบอร์เนตเริ่มต้นเอนทิตี; ส่วนตัวได้รับอนุญาต แต่จำเป็นต้องมีการเปิดเผยแพคเกจส่วนตัว (หรือสาธารณะ) สำหรับการสร้างรันไทม์พร็อกซีและการดึงข้อมูลที่มีประสิทธิภาพโดยไม่ต้องใช้เครื่องมือ bytecode
ฟิลด์ / อสังหาริมทรัพย์
ใช้การเข้าถึงฟิลด์โดยทั่วไปและการเข้าถึงคุณสมบัติเมื่อจำเป็น
เหตุผล: นี่อาจเป็นปัญหาที่ถกเถียงกันมากที่สุดเนื่องจากไม่มีข้อโต้แย้งที่ชัดเจนและน่าเชื่อถือสำหรับข้อใดข้อหนึ่งหรือข้ออื่น (การเข้าถึงคุณสมบัติเทียบกับการเข้าถึงฟิลด์) อย่างไรก็ตามการเข้าถึงฟิลด์ดูเหมือนจะเป็นรายการโปรดทั่วไปเนื่องจากรหัสที่ชัดเจนกว่าการห่อหุ้มที่ดีขึ้นและไม่จำเป็นต้องสร้างตัวตั้งค่าสำหรับฟิลด์ที่ไม่เปลี่ยนรูป
งด setters สำหรับฟิลด์ที่ไม่เปลี่ยนรูป (ไม่จำเป็นสำหรับฟิลด์ประเภทการเข้าถึง)
- คุณสมบัติอาจเป็น
เหตุผลส่วนตัว: ฉันเคยได้ยินว่าการป้องกันดีกว่าสำหรับประสิทธิภาพ (ไฮเบอร์เนต) แต่สิ่งที่ฉันพบได้บนเว็บคือ: ไฮเบอร์เนตสามารถเข้าถึงวิธีการเข้าถึงสาธารณะส่วนตัวและป้องกันรวมถึงฟิลด์สาธารณะโดยตรงและได้รับการป้องกันโดยตรง . ตัวเลือกขึ้นอยู่กับคุณและคุณสามารถจับคู่ให้เหมาะกับการออกแบบแอปพลิเคชันของคุณ
เท่ากับ / hashCode
- อย่าใช้รหัสที่สร้างขึ้นหากมีการตั้งค่ารหัสนี้เฉพาะเมื่อยังคงมีเอนทิตีอยู่
- ตามค่ากำหนด: ใช้ค่าที่ไม่เปลี่ยนรูปแบบเพื่อสร้างรหัสธุรกิจที่ไม่ซ้ำกันและใช้สิ่งนี้เพื่อทดสอบความเท่าเทียมกัน
- หากไม่มีรหัสธุรกิจที่ไม่ซ้ำให้ใช้UUIDที่ไม่ได้ชั่วคราวซึ่งสร้างขึ้นเมื่อมีการเริ่มต้นเอนทิตี ดูบทความที่ดีนี้สำหรับข้อมูลเพิ่มเติม
- อย่าอ้างถึงหน่วยงานที่เกี่ยวข้อง (ManyToOne) หากเอนทิตีนี้ (เช่นเอนทิตีหลัก) จำเป็นต้องเป็นส่วนหนึ่งของคีย์ธุรกิจให้เปรียบเทียบ ID เท่านั้น โทร getId () ในพร็อกซี่จะไม่เรียกการโหลดของกิจการตราบใดที่คุณกำลังใช้ประเภทการเข้าถึงสถานที่ให้บริการ
เอนทิตีตัวอย่าง
@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
}
คำแนะนำอื่น ๆ ที่จะเพิ่มในรายการนี้เป็นมากกว่ายินดีต้อนรับ ...
UPDATE
ตั้งแต่อ่านบทความนี้ฉันได้ปรับวิธีการใช้ eq / hC:
- ถ้ามีคีย์ธุรกิจแบบง่ายที่ไม่เปลี่ยนรูปให้ใช้: ใช้มัน
- ในกรณีอื่น ๆ ทั้งหมด: ใช้ uuid
final
(ตัดสินโดยการงดเซทเทอร์ของคุณฉันจะเดาว่าคุณก็ทำเช่นเดียวกัน)
notNull
มาจากไหน?