Если вы хотите использовать equals()/hashCode()
для своих Наборов, в том смысле, что одна и та же сущность может быть там только один раз, тогда есть только один вариант: Вариант 2. Это потому, что первичный ключ для сущности по определению никогда не меняется (если кто-то действительно ее обновляет, это уже не та сущность)
Вы должны понимать это буквально: поскольку ваши equals()/hashCode()
основаны на первичном ключеВы не должны использовать эти методы, пока не установлен первичный ключ.Таким образом, вы не должны помещать сущности в набор, пока им не назначен первичный ключ.(Да, UUID и подобные концепции могут помочь в раннем назначении первичных ключей.)
Теперь теоретически также возможно достичь этого с помощью варианта 3, хотя так называемые «бизнес-ключи» имеют неприятный недостаток, заключающийся в том, чтоони могут измениться: «Все, что вам нужно сделать, это удалить уже вставленные объекты из набора (ов) и повторно вставить их».Это правда, но это также означает, что в распределенной системе вам нужно будет убедиться, что это делается абсолютно везде, куда были вставлены данные (и вы должны быть уверены, что обновление выполнено, прежде чем что-то произойдет).Вам потребуется сложный механизм обновления, особенно если некоторые удаленные системы в настоящее время недоступны ...
Вариант 1 можно использовать только в том случае, если все объекты в ваших наборах находятся в одном сеансе Hibernate.В документации Hibernate об этом очень ясно говорится в главе 13.1.3.Учитывая идентичность объекта :
В рамках сеанса приложение может безопасно использовать == для сравнения объектов.
Однако приложение, использующее == вне сеанса, может привести кнеожиданные результаты.Это может произойти даже в некоторых неожиданных местах.Например, если вы поместите два отдельных экземпляра в один и тот же набор, оба могут иметь одинаковый идентификатор базы данных (т. Е. Они представляют одну и ту же строку).Однако идентичность JVM по определению не гарантируется для экземпляров в отключенном состоянии.Разработчик должен переопределить методы equals () и hashCode () в постоянных классах и реализовать свое собственное понятие равенства объектов.
Он продолжает спорить в пользу варианта 3:
Есть одно предупреждение: никогда не используйте идентификатор базы данных для реализации равенства.Используйте бизнес-ключ, который представляет собой комбинацию уникальных, обычно неизменных, атрибутов.Идентификатор базы данных изменится, если временный объект станет постоянным.Если временный экземпляр (обычно вместе с отдельными экземплярами) содержится в наборе, изменение хеш-кода нарушает контракт набора.
Это верно, , если you
- не может назначить идентификатор досрочно (например, с помощью UUID)
- , и все же вы абсолютно хотите поместить свои объекты в наборы, пока они находятся в переходном состоянии.
В противном случае вы можете выбрать вариант 2.
Тогда он упоминает о необходимости относительной стабильности:
Атрибуты для бизнес-ключей не обязательно должны быть такими же стабильными, какпервичные ключи базы данных;вам нужно только гарантировать стабильность, пока объекты находятся в одном наборе.
Это правильно.Практическая проблема, которую я вижу в этом: если вы не можете гарантировать абсолютную стабильность, как вы сможете гарантировать стабильность «до тех пор, пока объекты находятся в одном наборе».Я могу вообразить некоторые особые случаи (например, использовать наборы только для разговора, а затем выбросить его), но я бы поставил под сомнение общую практичность этого.
Короткая версия:
- Вариант 1 можно использовать только с объектами в пределах одного сеанса.
- Если вы можете, используйте Вариант 2. (Назначьте PK как можно раньше, потому что вы не можете использовать объекты в наборах до тех пор, пока PKназначен.)
- Если вы можете гарантировать относительную стабильность, вы можете использовать Вариант 3. Но будьте осторожны с этим.