Почему equals() у JPA-сущности почти всегда сломан
Вопрос проверяет, понимаете ли вы разницу между identity сущности в памяти и identity в базе. Самый частый вариант в коде — id-based equals со сравнением через getClass().
Проблема первая: у двух transient сущностей id ещё null. Если equals сравнивает id, оба null равны друг другу — два разных объекта окажутся "равны", хотя ни один не сохранён.
Проблема вторая: Hibernate возвращает не сам класс сущности, а proxy-подкласс для lazy-загрузки. getClass() у proxy и у реального объекта — разные классы, даже если id совпадает. Сравнение через instanceof работает, через getClass() ломается молча.
@Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Order other)) { return false; } return id != null && id.equals(other.id); }
Спросят следом: почему нельзя добавить все поля в equals, как предлагает IDE. Ответ — бизнес-поля меняются после сохранения, id стабилен. И почему equals должен возвращать false, если оба id null, а не true, как в наивной реализации через Objects.equals.
equals у сущности — это не про удобство коллекций, это про то, понимаете ли вы жизненный цикл объекта в JPA.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки