SpringBoot и @JoinTable

Потратил на эту проблему несколько часов. Чисто из-за собственной глупости. Сидел и отлаживал с точками остановки код Hibernate, чтобы понять, что происходит, но в итоге всё же нашёл на источник проблемы, хотя как мне кажется, он был вполне очевидным.

Проблема была в отображении связи М:М:

В этом куске кода происходит отображение связи трёх таблиц:

Диаграмма «сущность-связь» для связи М:М
Диаграмма «сущность-связь» связи М:М для таблиц pet, pet_book, book

В таблицах book и pet показаны только первичные ключи, чтобы не загромождать рисунок лишней информацией.

Проблема с кодом выше заключалась в том, что отображение на таблицы идеально отрабатывало в примере для Spring Framework, но при попытке выборки записей для коллекции books падало с ошибкой в примере для Spring Boot:

Как видно из текста ошибки, Hibernate для Spring Boot почему-то отображает @ManyToMany через промежуточную таблицу pet_books, что довольно странно.

В JavaDoc для аннотации @JoinTable написано, что если атрибут аннотации name не заполнен, то имя таблицы генерируется как имена таблиц двух связанных сущностей, разделённые символом подчёркивания. Откуда взялось множественное число books для варианта со Spring Boot?

Можно конечно, вручную выставить имя таблицы в атрибуте name аннотации @JoinTable, но мне нужен был пример с отсутствующим атрибутом name для книги.

Сейчас я прекрасно понимаю, вполне было очевидно, что проблема в стратегии именования. В логической стратегии именования или физической. Но тогда я что-то затупил. Однако в процессе отладки нашёл класс, который генерирует pet_books:

Класс SpringImplicitNamingStrategy наследуется от ImplicitNamingStrategyJpaCompliantImpl и переопределяет метод determineJoinTableName, генерируя имя таблицы как конкатенацию имени таблицы сущности, владеющей связью, и имени поля. А имя поля в нашем случае как раз books, вот и получается pet_books.

Сложно сказать, для чего в Spring Boot ввели свою стратегию именования, отличающуюся от Jakarta Persistence API, но исправить очень легко, нужно просто в файле “application.properties” выставить implicit_naming_strategy = default:

Значение default — это сокращённая запись для org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.

Один комментарий к “SpringBoot и @JoinTable”

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *