Ошибка отображения таблицы Hibernate в HQL-запросе

У меня есть веб-приложение, которое использует Hibernate для выполнения операций CRUD над базой данных. Я получил сообщение о том, что таблица не сопоставлена. Смотрите файлы Java:

Сообщение об ошибке:

org.springframework.orm.hibernate3.HibernateQueryException: Books is not mapped [SELECT COUNT(*) FROM Books]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: Books is not mapped [SELECT COUNT(*) FROM Books]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:660)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
...
Caused by: org.hibernate.hql.ast.QuerySyntaxException: Books is not mapped [SELECT COUNT(*) FROM Books]
at org.hibernate.hql.ast.util.SessionFactoryHelper.requireClassPersister(SessionFactoryHelper.java:181)
at org.hibernate.hql.ast.tree.FromElementFactory.addFromElement(FromElementFactory.java:111)
at org.hibernate.hql.ast.tree.FromClause.addFromElement(FromClause.java:93)
...

Вот мой метод DAO.java:

public int getTotalBooks(){
    return DataAccessUtils.intResult(hibernateTemplate.find(
          "SELECT COUNT(*) FROM Books"));
}

Book.java:

@Entity
@Table(name="Books")
public class Book {

    @Id
    @GeneratedValue
    @Column(name="id")
    private int id;

    @Column(name="title", nullable=false)
    private String title;
    ...
}

Как я должен изменить это, чтобы работать?

Ответ 1

Что говорит сообщение об исключении? В нем говорится:

Books is not mapped [SELECT COUNT(*) FROM Books]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: Books is not mapped [SELECT COUNT(*) FROM Books]

Что это говорит вам? Он сообщает вам, что Books не отображается. То есть нет сопоставленного типа с именем Books.

И действительно, нет. Тип вашего отображения называется Book. Он сопоставлен с таблицей Books, но тип называется Book. Когда вы пишете запросы HQL (или JPQL), вы используете имена типов, а не таблицы.

Итак, измените свой запрос на:

select count(*) from Book

Хотя я думаю, что это может быть

select count(b) from Book b

Если HQL не поддерживает нотацию *.

Вы можете учиться на чтении сообщений об исключениях!

Ответ 2

hibernate3.HibernateQueryException: Books is not mapped [SELECT COUNT(*) FROM Books];

Hibernate пытается сказать, что он не знает сущности с именем "Книги". Давайте посмотрим на вашу сущность:

@javax.persistence.Entity
@javax.persistence.Table(name = "Books")
public class Book {

Правильно. Имя таблицы для Book было переименовано в "Книги", но имя сущности по-прежнему является "Книгой" из имени класса. Если вы хотите установить имя объекта, вы должны использовать вместо него имя аннотации @Entity:

// this allows you to use the entity Books in HQL queries
@javax.persistence.Entity(name = "Books")
public class Book {

Это устанавливает как имя объекта, так и имя таблицы.


Противоположная проблема возникла со мной, когда я Person.hbm.xml файла Person.hbm.xml к использованию аннотаций Java для описания полей гибернации. Мой старый XML файл имел:

<hibernate-mapping package="...">
    <class name="Person" table="persons" lazy="true">
       ...
</hibernate-mapping>

И у моей новой сущности был @Entity(name=...) который мне был нужен, чтобы установить имя таблицы.

// this renames the entity and sets the table name
@javax.persistence.Entity(name = "persons")
public class Person {
    ...

Затем я увидел ошибки HQL, такие как:

QuerySyntaxException: Person is not mapped
     [SELECT id FROM Person WHERE id in (:ids)]

Проблема с этим заключалась в том, что имя сущности переименовывалось и для persons. Я должен был установить имя таблицы с помощью:

// no name = here so the entity can be used as Person
@javax.persistence.Entity
// table name specified here
@javax.persistence.Table(name = "persons")
public class Person extends BaseGeneratedId {

Надеюсь, что это помогает другим.

Ответ 3

Этот ответ приходит поздно, но суммирует концепцию, участвующую в исключении "table not mapping" (чтобы помочь тем, кто сталкивается с этой проблемой, поскольку она очень распространена для новичков спящего режима). Эта ошибка может появиться по многим причинам, но целью является решение наиболее распространенной проблемы, с которой сталкиваются многие начинающие разработчики спящего режима, чтобы сохранить их в течение нескольких часов исследований. Я использую свой собственный пример для простой демонстрации ниже.

Исключение:

org.hibernate.hql.internal.ast.QuerySyntaxException: subscriber is not mapped [ from subscriber]

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

Session session = this.sessionFactory.getCurrentSession();
List<Subscriber> personsList = session.createQuery(" from subscriber").list();

Так объявлен класс POJO:

@Entity
@Table(name = "subscriber")
public class Subscriber

Но синтаксис запроса "от абонента верен, а таблица subscriber существует. Это подводит меня к ключевому моменту:

  • Это запрос HQL, а не SQL.

и как описывается здесь

HQL работает с постоянными объектами и их свойствами, а не с таблицами и столбцами базы данных.

Поскольку вышеупомянутый запрос является HQL-кодом, subscriber должен быть именем сущности, а не именем таблицы. Поскольку у меня есть таблица subscriber, сопоставленная с сущностью subscriber. Моя проблема решается, если я изменю код на это:

Session session = this.sessionFactory.getCurrentSession();
List<Subscriber> personsList = session.createQuery(" from subscriber").list();

Просто чтобы вы не путались. Обратите внимание, что HQL чувствителен к регистру в ряде случаев. В противном случае это сработало бы в моем случае.

Ключевые слова, такие как SELECT, FROM и WHERE и т.д., не чувствительны к регистру, но свойства, такие как имена таблиц и столбцов, чувствительны к регистру в HQL.

https://www.tutorialspoint.com/hibernate/hibernate_query_language.htm

Чтобы понять, как работает отображение спящего режима, прочитайте this

Ответ 4

Спасибо всем. Много хороших идей. Это мое первое приложение в Spring и Hibernate.. так немного больше терпения при работе с "новичками", как я..

Пожалуйста, прочитайте ответы Тома Андерсона и Романа К. Они очень хорошо объяснили эту проблему. И все вы помогли мне. Я заменил

SELECT COUNT(*) FROM Books

с

select count(book.id) from Book book

И, конечно, у меня есть этот Spring config:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="packagesToScan" value="extjs.model"/>

Еще раз спасибо!

Ответ 5

В конфигурации Spring typo applicationContext.xml, где сконфигурированное sessionFactory помещает это свойство

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="packagesToScan" value="${package.name}"/>

Ответ 6

Hibernate также требователен к капитализации. По умолчанию это будет имя класса с первой буквой заглавной. Так что если ваш класс называется FooBar, не передавайте "foobar". Вы должны передать "FooBar" с точной заглавной буквы, чтобы он работал.

Ответ 7

В дополнение к принятому ответу, еще одна проверка должна убедиться, что у вас есть правильная ссылка на ваш пакет сущностей в sessionFactory.setPackagesToScan(...) при настройке фабрики сеансов.