Я працюю з JPA (реалізація в режимі глибокого сну) протягом деякого часу, і кожен раз, коли мені потрібно створювати об'єкти, я стикаюся з такими проблемами, як AccessType, незмінні властивості, equals / hashCode, ....
Тому я вирішив спробувати знайти загальну найкращу практику для кожного випуску і записати це для особистого використання.
Я б не заперечував проти того, щоб хтось прокоментував це чи сказав мені, де я помиляюся.
Клас сутності
реалізувати Serializable
Причина: Специфікація говорить про те, що потрібно, але деякі постачальники JPA цього не застосовують. Зимова сплячка як постачальник JPA цього не застосовує, але вона може вийти з ладу десь глибоко в шлунку за допомогою ClassCastException, якщо Serializable не буде впроваджено.
Конструктори
створити конструктор з усіма необхідними полями сутності
Причина: Конструктор повинен завжди залишати створений екземпляр у здоровому стані.
крім цього конструктора: мати пакет приватного конструктора за замовчуванням
Причина: конструктор за замовчуванням зобов’язаний Hibernate ініціалізувати об'єкт; приватне дозволено, але приватна (або загальнодоступна) видимість пакету потрібна для створення проксі-серверів виконання та ефективного пошуку даних без інструментарію байт-коду.
Поля / Властивості
Використовуйте доступ до поля загалом та доступ до власності, коли це необхідно
Причина: це, мабуть, найбільш дискусійне питання, оскільки немає чітких та переконливих аргументів для того чи іншого (доступ власності проти доступу до поля); однак, доступ до поля, здається, є загальним улюбленим через чіткіший код, кращу інкапсуляцію та відсутність необхідності створювати задачі для змінних полів
Опустіть сеттери для змінних полів (не потрібно для поля типу доступу)
- властивості можуть бути приватними
Причина: Я колись чув, що захищений краще для (Hibernate) продуктивності, але все, що я можу знайти в Інтернеті, це: Hibernate може отримати доступ до публічних, приватних та захищених методів доступу, а також до публічних, приватних та захищених полів безпосередньо . Вибір залежить від вас, і ви зможете зіставити його відповідно до дизайну програми.
Дорівнює / hashCode
- Ніколи не використовуйте згенерований ідентифікатор, якщо цей ідентифікатор встановлений лише при збереженні сутності
- За перевагою: використовуйте незмінні значення для формування унікального бізнес-ключа та використовуйте це для перевірки рівності
- якщо унікальний бізнес-ключ недоступний, використовуйте неперехідний UUID, який створюється під час ініціалізації об'єкта; Дивіться цю чудову статтю для отримання додаткової інформації.
- ніколи не посилайтеся на пов’язані особи (ManyToOne); якщо ця особа (як материнське підприємство) має бути частиною бізнес-ключа, то порівняйте лише ідентифікатори. Виклик 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
}
Інші пропозиції додати до цього списку більш ніж вітаються ...
ОНОВЛЕННЯ
Після прочитання цієї статті я адаптував свій спосіб реалізації eq / hC:
- якщо доступний незмінний простий бізнес-ключ: скористайтеся цим
- у всіх інших випадках: використовуйте uuid
final
(судячи з вашої відсутності сетерів, я б, мабуть, ви теж зробили).
notNull
?