Будет ли работать сущность в Hibernate, если в mapping указаны не все компоненты составного первичного ключа
Что проверяют
Понимаете ли вы, что Hibernate не сверяет маппинг с настоящим первичным ключом таблицы и доверяет тому, что вы объявили через @Id. Следом просят описать, что именно сломается и как правильно маппить составной ключ.
Как отвечать
Короткий ответ: запустится и какое-то время даже будет работать. Hibernate считает идентификатором ровно те поля, что помечены @Id или вынесены в @EmbeddedId. Схему он не проверяет: ddl-auto=validate смотрит на таблицы, колонки и типы, но не на состав первичного ключа.
Что происходит дальше, зависит от данных. Если объявленная часть ключа на деле уникальна, всё работает. Если нет, проблемы тихие и неприятные:
- чтение по id:
find()получает несколько строк на один идентификатор и падает с ошибкой, что строк с таким идентификатором больше одной; - запросы списком: persistence context держит один объект на один идентификатор, поэтому строки с совпадающей частью ключа превращаются в один экземпляр. Размер списка верный, а данные повторяют первую строку;
- UPDATE и DELETE: условие
WHEREстроится по неполному ключу и задевает все строки с таким значением. Hibernate сверяет число затронутых строк с ожидаемым и обычно бросает исключение, но данные это спасает только при откате транзакции; - INSERT: если незамапленная колонка ключа
NOT NULLбез значения по умолчанию, вставку отклонит база.
Правильный маппинг включает все колонки ключа в одном из двух вариантов: @EmbeddedId с классом @Embeddable или @IdClass с повторением полей через @Id. Класс ключа реализует Serializable, переопределяет equals и hashCode по всем полям и имеет конструктор без аргументов. С Hibernate 6 аннотации берутся из jakarta.persistence, а не из javax.persistence.
Где спотыкаются
Отвечают «Hibernate сразу выбросит исключение». Не выбросит: ошибки появятся только на конкретных данных, часто уже в проде.
Не узнают симптом «список из одинаковых объектов». Это классическая картина неуникального @Id, особенно при маппинге представлений.
Забывают equals и hashCode в классе ключа. Тогда поиск в кеше первого уровня и работа с коллекциями ведут себя непредсказуемо.