Как сопоставить поле объекта, имя которого является зарезервированным словом в JPA

92
@Column(name="open")

Использование диалекта sqlserver с hibernate.

[SchemaUpdate] Unsuccessful: create table auth_session (id numeric(19,0) identity not null, active tinyint null, creation_date datetime not null, last_modified datetime not null, maxidle int null, maxlive int null, open tinyint null, sessionid varchar(255) not null, user_id numeric(19,0) not null, primary key (id), unique (sessionid))
[SchemaUpdate] Incorrect syntax near the keyword 'open'.

Я ожидал, что hibernate будет использовать указанный в кавычках идентификатор при создании таблицы.

Есть идеи, как с этим справиться ... кроме переименования поля?

TJR
источник
См., Например, hibernate.onjira.com/browse/HHH-1272
Ondra ižka

Ответы:

55

Была та же проблема, но с именем таблицы Transaction. Если вы установите

hibernate.globally_quoted_identifiers=true

Тогда будут указаны все идентификаторы базы данных.

Нашел здесь свой ответ Специальный символ в имени таблицы, вызывающий ошибку гибернации

И нашел все доступные настройки здесь https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/appendices/Configurations.html

Не удалось найти лучших документов для этого.

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

Рафиек
источник
9
Почему это не настройка по умолчанию?
Джош М.
SQL может стать нечитаемым, и использование ключевых слов в качестве имен - плохая практика, которую не следует поощрять. Я думаю...?
Rafiek
1
Ладно. Я предпочитаю использовать зарезервированное слово в качестве имени в течение всего дня, а не имя, которое не подходит.
Джош М.
Да, вы можете сказать, что абстракция, предоставляемая Hibernate, вызывает беспокойство, а не то, как она технически реализована. Но если вы также используете такие инструменты, как Flyway или Liquibase, это усложняет ситуацию, когда вам нужно учитывать, что могут быть зарезервированные слова. Это был мой опыт при переносе схемы.
Rafiek
2
Для тех, кто задается вопросом, где это нужно установить, вероятно, это в ваших persistence.xmlпроектах для JBoss.
Addison
138

Используя Hibernate в качестве поставщика JPA 1.0, вы можете избежать зарезервированного ключевого слова, заключив его в обратные кавычки:

@Column(name="`open`")

Это синтаксис, унаследованный от Hiberate Core:

5.4. Идентификаторы в кавычках SQL

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

<class name="LineItem" table="`Line Item`">
    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
    <property name="itemNumber" column="`Item #`"/>
    ...
</class>

В JPA 2.0 синтаксис стандартизирован и становится следующим:

@Column(name="\"open\"")

Ссылки

Связанные вопросы

Паскаль Тивент
источник
И спасибо от меня. Это решило мою проблему. btw - Ссылка теперь находится по адресу: docs.jboss.org/hibernate/stable/core/manual/en-US/html/…
Стив,
5
Я не понимаю, почему я должен это делать, почему Hibernate не делает это автоматически вместо меня ???
Daniel Hári
@ DanielHári, может быть, ты находишь мой ответ более "автоматическим"?
Rafiek
1
@Rafiek: О да, это идеальное решение, проголосовало за (y).
Daniel Hári
1
Использование @Column(name="[open]")намного красивее :)
Валид Абдалмаджид
16

Экранирование зарезервированных ключевых слов вручную

Если вы используете JPA, вы можете избежать двойных кавычек:

@Column(name = "\"open\"")

Если вы используете собственный API Hibernate, вы можете избежать их с помощью обратных кавычек:

@Column(name = "`open`")

Автоматическое экранирование зарезервированных ключевых слов

Если вы хотите автоматически экранировать зарезервированные ключевые слова, вы можете установить свойство конфигурации, trueспецифичное для Hibernate hibernate.globally_quoted_identifiers:

<property
    name="hibernate.globally_quoted_identifiers"
    value="true"
/>

Формат ямл

spring:
  jpa:
    properties:
      hibernate:
        globally_quoted_identifiers: true

Подробнее читайте в этой статье .

Влад Михалча
источник
15

Если вы используете, как показано ниже, он должен работать

@Column(name="[order]")
private int order;
Раман
источник
Вы просто делаете это в частном поле, а не в геттере?
Джейк Гастон
5
это специфично для sqlserver.
Alfredo M
11
@Column(name="\"open\"")

Это наверняка сработает. Та же проблема случилась со мной, когда я изучал спящий режим.

wmnitin
источник
4

Нет - измените название столбца.

Это зависит от базы данных, и вы просто не можете создать такой столбец. В конце концов, hibernate отправляет DDL в базу данных. Если вы не можете создать допустимый DDL с этим именем столбца, это означает, что спящий режим тоже не может. Я не думаю, что цитирование решило бы проблему, даже если вы пишете DDL.

Даже если вам как-то удастся избежать названия - измените его. Он будет работать с этой базой данных, но не будет работать с другой.

Божо
источник
Это может сработать. См. Stackoverflow.com/questions/285775/… . Подождем подтверждения OP.
ewernli
1
Это не зависит от базы данных! Вы экранируете его с помощью `и переводите в спящий режим в правильном стиле цитирования для диалекта SQL
Даниэль
2

Некоторые реализации JPA (например, тот, который я использую, DataNucleus) автоматически цитируют идентификатор для вас, поэтому вы никогда не получите его.

Нил Стоктон
источник
Да, удивлен, что Hibernate, по-видимому, все еще не предлагает такой базовой функции, учитывая количество раз, когда люди попадают в нее (и кто-то даже проголосовал против вас за то, что вы осмелились упомянуть, что это было возможно в другом месте)