Подтвердить что ты не робот

Должно ли поле id объекта JPA рассматриваться равным и hashCode?

Я столкнулся с проблемой при написании тестов для приложения базы данных с использованием JPA2 и EclipseLink:

Я добавляю какой-то объект в базу данных, извлекаю его позже и хочу сравнить его с экземпляром, который имеет значения, которые я ожидаю, чтобы подтвердить, что сложение работает так, как я предполагал.

Сначала я написал что-то вроде

assertEquals(expResult, dbResult);

который не удалось, потому что я не могу знать значение поля id, которое генерируется базой данных, и поэтому dbResult отличается от expResult, который я создал с помощью new, и заполнен вручную.

Я вижу два варианта:

  • Либо я удаляю поле id из equals и hashCode, чтобы сравнение было основано только на "реальных значениях". Я не знаю, вызвало ли это проблемы в базе данных или в других местах.

  • Или я пишу свои тесты, чтобы явно проверять каждое поле, кроме id вручную.

Что мне делать?

4b9b3361

Ответ 1

Вы можете найти много споров об этом. Моя позиция заключается в том, что вы абсолютно не используете первичный ключ базы данных для чего-либо в своем приложении. Он должен быть полностью невидим. Определите свои объекты в приложении другим свойством или комбинацией свойств.

На фронте операций тестирования настойчивости вам действительно нужно проверить, правильно ли были сохранены и загружены поля, и, возможно, первичный ключ получил определенное значение при его сохранении. Это, вероятно, совсем не работает для метода equals.

Ответ 2

Из книги Hibernate in Action рекомендуется использовать бизнес-ключ и проверить на нем равенство. Бизнес-ключ - это свойство или некоторая комбинация свойств, которая уникальна для каждого экземпляра с одинаковым идентификатором базы данных ". В других областях говорится, что он не использует идентификатор как одно из этих свойств и не использует значения в коллекциях.

Ответ 3

Опираясь на созданные в базе данных идентификаторы в вашей реализации equals и hashCode не рекомендуется. Вы должны полагаться на поистине уникальные/полу-уникальные атрибуты ваших классов при проверке равенства и генерации значений хэш-кода. Документация Hibernate содержит обширную страницу, на которой это обсуждается, и факты в ней применимы к более или менее каждому поставщику JPA.

Основная причина использования бизнес-ключей по генерируемым базам значениям в вашей реализации equals и hashCode заключается в том, что поставщик JPA должен фактически выпустить SELECT после сохранения объекта в базе данных. Если вы сравниваете объекты с использованием идентификаторов, сгенерированных с помощью базы данных, тогда вы получите тест равенства, который не выполняется в следующих сценариях:

  • Если E1 и E2 являются объектами класса E (которые проверяют равенство с использованием генерируемых идентификаторами базы данных), то если E1 и E2 будут равны, если они еще не были сохранены в базе данных. Это не то, что вы хотите, особенно если хотите сохранить E1 и E2 в некотором Set перед сохранением. Это хуже, если атрибуты E1 и E2 имеют разные значения; реализация equals предотвратила бы добавление двух существенно разных объектов в Set, а реализация hashCode даст вам время поиска O(n), когда сущности просматриваются с помощью HashMap с использованием первичного ключа.
  • Если E1 является управляемым объектом, который был сохранен, а E2 является сущностью, которая не была сохранена, тогда тест равенства будет считать, что E1!= E2 в сценарии, где все значения атрибутов E1 и E2 (кроме идентификаторов) аналогичны. Опять же, это, вероятно, не то, что вы хотите, особенно если вы хотите избежать дублирования сущностей в базе данных, которые отличаются только идентификаторами, создаваемыми в базе данных.

Таким образом, реализации equals и hashCode должны использовать бизнес-ключи, чтобы демонстрировать согласованное поведение как для сохраняемых, так и для непервизированных объектов.

Ответ 4

Я бы написал свой тест, чтобы явно проверить поля. Чтобы сделать это проще, перед выполнением теста assertEqual я установил идентификатор как ожидаемого, так и фактического результата в одно и то же предопределенное значение, а затем применил метод normal equals.

Удаление идентификатора из равных не оправдано, просто потому, что тестирование немного затруднено. Вы отказываетесь от серьезных преимуществ, а также целостности кода.