Как стать автором
Обновить

Комментарии 8

Лишний геморрой. Скрипты, генерируемые хибером, а "под капотом" именно они и используются, довольно посредственного качества, в том числе и из-за упомянутых нюансов с переименованием столбцов.

В фазу накатывания ликвибэйзовых скриптов нужно добавлять верификатор соответствия того, что в БД есть и того, что на сущностях наразмечали. И откатывать при несоответствии.

Я тоже не стесняюсь использовать Lombok в проектах и JPA-сущностях по полной, но должен предупредить автора о наличии в коде проблем. У вас @Data на сущностях с двусторонними взаимоотношениями — там по умолчанию есть @ToString и будет Stack Overflow при попытке вывести сущность в лог. Да и hashCode и equals тоже будут на него напарываться.

Всё это описывает вот эта вполне себе "классическая" статья: https://thorben-janssen.com/lombok-hibernate-how-to-avoid-common-pitfalls/

Лучше добавить @EqualsAndHashCode.Include на единственное корректное для этого поле — id, и над каждой сущностью дополнительно @EqualsAndHashCode(onlyExplicitlyIncluded=true).

Опять же для id это может быть не всегда верно, т.к. при создание entity поле не будет заполнено, а после сохранения заполнится -> т.е. сущность изменится(и если она была добавлена в map до сохранения, то по хеш коду ее уже не получится найти).
Но в статье приведен абстрактный пример entity, поэтому тут подходят любые варианты.

Опять же для id это может быть не всегда верно, т.к. при создание entity поле не будет заполнено

Да, поэтому если id равен null equals должен возвращать false. Независимо от того, чему равен id другой энтити. А чтобы можно было найти сущность после появления id, нужно из hashCode всегда возвращать 31

Да, поэтому если id равен null equals должен возвращать false.

Мне кажется это нарушит принцип рефлексивности: для любой ненулевой ссылки на значение х выражение х.equals(х) должно возвращать true.


А чтобы можно было найти сущность после появления id, нужно из hashCode всегда возвращать 31

Так делать лучше не стоит, т.к. при возврате константы вся производительность хеш-таблиц сведеться к массиву.
Может вы путаете с числом, на которое нужно умножать(сдвигать) полученный результат при вычисление хеш-кода? по книге Джошуа Блоха, это как раз число 31.

по поводу lombok и jpa можно почитать эту статью. Если планируется использовать jpa entity в мапах, сетах и сравнивать, лучше самостоятельно переопределить методы equals и hashCode. А если достаточно просто сохранять, получать данные из бд, мапить их в дто, то вполне можно не обращать особого внимание на пустой ид до создания сущности и не очень производительный метода equals(если он нужен только при сравнение ожидаемых результатов в юнит тестах)

Мне кажется это нарушит принцип рефлексивности: для любой ненулевой ссылки на значение х выражение х.equals(х) должно возвращать true.

Поэтому в первой строке надо возвращать true, если в метод equals пришёл тот самый, у которого вызывается метод.


Так делать лучше не стоит, т.к. при возврате константы вся производительность хеш-таблиц сведеться к массиву.

Не к массиву, а к связному списку. В лучшем случае к дереву. Но в случае с энтити это не важно, потому что использовать энтити в качестве ключей в HashMap категорически не рекомендуется. В том числе по озвученой вами причине. Есть ещё случай, когда у энтити есть коллекция дочерних элементов и тип коллекции — Set. Но в такой коллекции не должно быть много элементов. Если этих элементов много — оформлять такую связь через JPA категорически не рекомендуется, потому что нельзя контролировать получение этих элементов из базы данных. Лучше просто сделать ссылку на родительскую сущность в дочерних сущностях, а OneToMany не писать.


Может вы путаете с числом, на которое нужно умножать(сдвигать) полученный результат при вычисление хеш-кода? по книге Джошуа Блоха, это как раз число 31.

Не путаю. Но 31 возвращать и правда не обязательно, можно вернуть и 42 )). Главное, чтобы все этити упали в один бакет.


по поводу lombok и jpa можно почитать эту статью.

Обратите внимание, к статье много моих комментариев по тому же поводу, что и здесь ))


Если планируется использовать jpa entity в мапах, сетах и сравнивать, лучше самостоятельно переопределить методы equals и hashCode.

Вы может и не планируете. А другой разработчик планирует и вас не спросит, потому что вы будете работать с кодом в разное время. И вполне вероятно, что он не знает, что надо сравнивать энтити только по id, возвращать false, если id == null и что hashCode() должен вернуть 31. И словит баги, которые воспроизводятся не очень часто, но очень метко. Он об этих багах наверное даже и не узнает и хорошо, если их поймают не в продакшне.


Особенно неприятно, если equals переопределили для тестов. Тогда даже если разработчик в курсе, что надо что-то делать с equals, он может на это забить. Потому что править все тесты с энтити ему может показаться скучным и неинтересным.


Поэтому для сравнения энтити в тестах лучше использовать методы типа reflectionEquals из AssertJ


P. S. Всё это, конечно, актуально только когда у энтити нет естественного ключа. Если он есть, то нужно использовать его

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории