Ответ
Переопределять equals нужно с осторожностью, соблюдая специфику JPA.
Ключевые принципы:
- Сравнение по идентификатору (
id) — наиболее распространённый подход, но только для сохранённых сущностей (когдаid != null). - Нельзя использовать изменяемые поля (кроме ID), так как это нарушит контракт
equals. - Учитывайте проблемы с прокси-объектами при ленивой загрузке (
HibernateProxy).
Рекомендуемая реализация (с учётом прокси и transient-состояния):
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false; // instanceof работает с прокси
User user = (User) o;
return id != null && id.equals(user.getId()); // Сравниваем только по ID, если он есть
}
@Override
public int hashCode() {
return getClass().hashCode(); // Константа для всех экземпляров класса
}
Почему так?
instanceofкорректно работает с Hibernate-прокси.hashCode()возвращает константу, что безопасно, пока сущность не сохранена (ID может бытьnull). После сохраненияequalsбудет корректно работать по ID.- Две transient-сущности (без ID) будут считаться не равными, что логично, так как это разные объекты в памяти, ещё не отождествлённые базой данных.