Прежде всего, ваша первоначальная идея, что вы должны реализовывать equals () и hashCode () только для неизменяемых объектов, безусловно, работает, но это строже, чем нужно.Вам просто нужны эти два метода, чтобы полагаться на неизменные поля.Любое поле, значение которого может измениться, не подходит для использования в этих двух методах, но другие поля не должны быть неизменными.
Сказав это, Hibernate знает, что это один и тот же объект, сравнивая их первичные ключи.Это приводит к тому, что многие пишут эти два метода, полагаясь на первичный ключ.Документы Hibernate рекомендуют не делать этого, но многие люди игнорируют этот совет без особых проблем.Это означает, что вы не можете добавлять сущности в набор до тех пор, пока они не будут сохранены, что является ограничением, с которым не так уж сложно жить.
В документах Hibernate рекомендуется использовать бизнес-ключ.Но бизнес-ключ должен опираться на поля, которые однозначно идентифицируют объект.В документах Hibernate говорится «используйте бизнес-ключ, который представляет собой комбинацию уникальных, обычно неизменяемых атрибутов».Я использую поля, которые имеют уникальные ограничения в базе данных.Итак, если ваш оператор Sql CREATE TABLE задает ограничение как
CONSTRAINT uc_order_num_item UNIQUE (order_num, order_item)
, то эти два поля могут быть вашим бизнес-ключом.Таким образом, если вы измените один из них, и Hibernate, и Java будут рассматривать измененный объект как другой объект.Конечно, если вы измените одно из этих «неизменяемых» полей, вы испортите любой набор, к которому они принадлежат.Поэтому я думаю, вам нужно четко задокументировать, какие поля составляют бизнес-ключ, и написать свое приложение, понимая, что поля в бизнес-ключе никогда не должны изменяться для постоянных объектов.Я понимаю, почему люди игнорируют совет и используют первичный ключ.Но вы можете определить первичный ключ следующим образом:
CONSTRAINT pk_order_num_item PRIMARY KEY (order_num, order_item)
И у вас все еще будет та же проблема.
Лично я хотел бы видеть аннотацию, которая определяет каждое поле в бизнесеключ, и есть проверка IDE, которая проверяет, изменил ли я его для постоянных объектов.Может быть, это требует слишком много.
Другой подход, который решает все эти проблемы, заключается в использовании UUID для первичного ключа, который вы генерируете на клиенте, когда вы впервые создаете неперспективную сущность.Так как вам никогда не нужно показывать это пользователю, ваш код вряд ли изменит свое значение после его установки.Это позволяет вам писать методы hashCode () и equals (), которые всегда работают и остаются согласованными друг с другом.
Еще одна вещь: если вы хотите избежать проблемы добавления объекта в набор, который уже содержитдругая (модифицированная) его версия, единственный способ - всегда спрашивать набор, если он уже есть, прежде чем добавлять его.Затем вы можете написать код для обработки этого особого случая.