Рубрики
Без рубрики

Стратегии именования в режиме гибернации: Спецификация JPA против мнения о весенней загрузке

Каждый раз, когда мы внедряем зависимость в наш проект, мы подписываем контракт, в котором часто много скрытого… Помечен как hibernate, java, spring boot, веб-разработчик.

Каждый раз, когда мы внедряем зависимость в наш проект, мы подписываем контракт, в котором часто много скрытых вещей, “написанных мелким шрифтом”. В этой статье мы рассмотрим то, что вы могли пропустить при подписании трехстороннего контракта между вами, Hibernate и Spring Boot. Мы поговорим о стратегиях именования.

Значения по умолчанию в именовании JPA

Главное правило, касающееся значений по умолчанию: они должны быть интуитивно понятными. Давайте проверим, применимо ли это правило к стандартному приложению Spring Boot с конфигурацией по умолчанию, использующей Hibernate в качестве реализации JPA. Представьте, что у вас есть сущность “Gettype” . Давайте угадаем, с каким именем таблицы в базе данных она связана.

Первый пример:

@Entity
public class PetType {
  // fields omitted
}

Для меня наиболее интуитивно понятным именем таблицы было бы имя класса, которое Тип питомца . Запустив тест против PostgreSQL, мы обнаруживаем, что имя связанной таблицы на самом деле тип питомца . Давайте зададим имя явно, используя @Таблица :

@Entity
@Table(name = "PetType")
public class PetType {
  // fields omitted
}

На этот раз мы ожидаем увидеть тип питомца наверняка, но если мы проведем тест… pet_type снова!

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

@Entity
@Table(name = "\"PetType\"")
public class PetType {
  // fields omitted
}

Опять же, наши ожидания оказались неверными, и мы видим "pet_type" , но теперь в кавычках!

Стратегии именования в режиме гибернации

Погуглив “имя таблицы сущности jpa по умолчанию” вы, скорее всего, наткнетесь на следующий результат :

Имя таблицы JPA по умолчанию – это имя класса (минус пакет) с заглавной первой буквой. Каждый атрибут класса будет сохранен в столбце таблицы.

Это именно то, что мы ожидали увидеть в первом примере, не так ли? Очевидно, что-то нарушает стандарт.

Давайте глубже погрузимся в спящий режим. Согласно документации, в гибернации есть два интерфейса, отвечающих за присвоение имен вашим таблицам, столбцам и т.д.: Имплицитное обозначение стратегии и Стратегия физического именования .

ImplicitNamingStrategy отвечает за присвоение имен всем объектам, которые явно не были названы разработчиком: например, имя сущности, имя таблицы, имя столбца, индекс, FK и т.д. Полученное имя называется логическим именем, оно используется внутри Hibernate для идентификации объекта. Это не то имя, которое помещается в базу данных.

PhysicalNamingStrategy предоставляет фактическое физическое имя, используемое в БД, на основе логического имени объекта JPA. Фактически это означает, что при использовании гибернации вы не можете указывать имена объектов базы данных напрямую, а только логические. Чтобы лучше понять, что происходит под капотом, посмотрите на диаграмму ниже.

Реализации этих интерфейсов в режиме гибернации по умолчанию являются ImplicitNamingStrategy Реализацией, совместимой с Jpa и Стандарт физической стратегии именования , применяемый . Первый генерирует логические имена в соответствии со спецификацией JPA, а второй использует их в качестве физических имен без каких-либо изменений. Это лучше всего описано в документации:

JPA определяет неотъемлемые правила определения неявного логического имени. Если переносимость поставщика JPA является серьезной проблемой, или если вам действительно нравятся правила неявного именования, определенные JPA, обязательно придерживайтесь implicitnamingstrategyjpacompliant.pl (значение по умолчанию). Кроме того, JPA не определяет разделения между логическим и физическим именем. В соответствии со спецификацией JPA логическое имя является физическим именем. Если важна переносимость поставщика JPA, приложениям следует предпочесть не указывать Стратегию физического именования .

Однако наше приложение демонстрирует другое поведение. И вот почему. Весенняя загрузка переопределяет реализации гибернации по умолчанию как для интерфейсов, так и для использования Весенняя имплицитнаястратегия и Вместо этого используйте физическую стратегию именования .

Эффективно, Spring ImplicitNamingStrategy копирует поведение ImplicitNamingStrategy, совместимого с Jpa, Impl с незначительной разницей в именовании таблиц соединений. Итак, это должно быть Весенняя стратегия физического именования это приводит к тем результатам, которые мы видели. В документации говорится следующее:

По умолчанию Spring Boot настраивает стратегию физического именования с помощью Spring PhysicalNamingStrategy . Эта реализация обеспечивает ту же структуру таблицы, что и в Hibernate 4: все точки заменяются символами подчеркивания, а верблюжья оболочка также заменяется символами подчеркивания. Кроме того, по умолчанию все имена таблиц генерируются в нижнем регистре. Например, объект Номер телефона сопоставляется с таблицей Номер телефона .

В принципе, это всегда трансформирует Чехол для верблюда и Паскаль-кейс чтобы змеиный кейс . На самом деле, с его помощью вообще невозможно работать с non_snake_case . Лично я бы никогда не стал использовать camelCase или PascalCase для именования объектов базы данных, но есть администраторы БД, которые могли бы. Если ваше приложение Spring Boot работает со сторонней базой данных, в которой хотя бы одна таблица или столбец определены в регистре pascal или camel, настройка Spring Boot по умолчанию не будет работать для вас. Поэтому убедитесь, что используемая стратегия physicalnamingstrategy поддерживает данное соглашение об именовании базы данных. Узнайте, как изменить стратегию именования по умолчанию, в этой статье или, при необходимости, узнайте, как предоставить свою собственную реализацию здесь.

Таким образом, Hibernate соответствует спецификации JPA, а Spring Boot – нет. Это может выглядеть как ошибка, но Spring Boot утверждает, что является самоуверенным фреймворком. Другими словами, он имеет полное право применять свое собственное мнение, общие стандарты и спецификации технологии, используемой под капотом. Для разработчика это означает следующее:

  • Мнение может переопределить любую спецификацию. Другими словами, спецификации и стандарты определяют, как это должно быть, в то время как используемая реализация определяет, что это такое на самом деле.
  • Если что-то даже работает по умолчанию, вы всегда должны знать, что это за значение по умолчанию и как именно оно работает.
  • Значения по умолчанию могут измениться при обновлении версии библиотеки, что может привести к непредсказуемым побочным эффектам.

Вывод

Магия конфигураций по умолчанию может работать до тех пор, пока вы не столкнетесь с неожиданным поведением. Чтобы избежать такого риска, вы можете предпочесть явное определение неявному использованию значений по умолчанию. Таким образом, в нашем случае рекомендация будет такой:

  1. Всегда называйте свои объекты JPA явно, чтобы никакая неявная стратегия именования не влияла на ваш код
  2. Используйте snake_case для имен столбцов, таблиц, индексов и других объектов JPA, чтобы избежать их преобразования при любой реализации Стратегии физического именования
  3. В случае snake_case не работает для вас (например, с использованием устаревшей базы данных), установите PhysicalNamingStrategy в PhysicalNamingStrategyStandardImpl

Явное присвоение имен объектам JPA также предотвратит нежелательные изменения схемы базы данных в случае рефакторинга класса сущности или имени поля.

Вы можете заметить, что при решении потенциальных проблем во время выполнения мы просто перекладываем ответственность на разработчиков, вводя соглашения об именовании. Теперь нам нужно убедиться, что все разработчики следуют одним и тем же правилам. Это можно автоматизировать, переложив эти обязанности на инструменты разработки.

Итак, если вы используете IntelliJ IDEA, вы можете попробовать JPA Buddy – плагин, предназначенный для помощи разработчикам с JPA, Hibernate, Spring Data JPA, Liquibase и другими связанными технологиями. JPA Buddy позволяет команде настраивать согласованные соглашения о коде и применять их для вновь созданных объектов JPA.

Оригинал: “https://dev.to/aleksey/hibernate-naming-strategies-jpa-specification-vs-spring-boot-opinionation-m1c”