Перейти к основному содержимому

Исключение сопоставления гибернации — неизвестная сущность

· 3 мин. чтения

1. Проблема

В этой статье мы обсудим проблему org.hibernate.MappingException : Неизвестная сущность и решения как для Hibernate, так и для среды Spring и Hibernate.

2. Отсутствует или недействительна аннотация @Entity

Наиболее распространенной причиной исключения сопоставления является просто класс сущности, в котором отсутствует аннотация @Entity :

public class Foo implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

public Foo() {
super();
}

public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}

Другая возможность заключается в том, что он может иметь неправильный тип аннотации @Entity :

import org.hibernate.annotations.Entity;

@Entity
public class Foo implements Serializable {
...

Устаревший org.hibernate.annotations.Entity — это неправильный тип сущности для использования — нам нужен javax.persistence.Entity :

import javax.persistence.Entity;

@Entity
public class Foo implements Serializable {
...

3. MappingException с Spring

Конфигурация Hibernate в Spring включает загрузку SessionFactory из сканирования аннотаций через LocalSessionFactoryBean :

@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
...
return sessionFactory;
}

В этой простой конфигурации компонента Session Factory отсутствует ключевой компонент, и тест, пытающийся использовать SessionFactory , завершится неудачей:

...
@Autowired
private SessionFactory sessionFactory;

@Test(expected = MappingException.class)
@Transactional
public void givenEntityIsPersisted_thenException() {
sessionFactory.getCurrentSession().saveOrUpdate(new Foo());
}

Исключением, как и ожидалось, является объект MappingException: Unknown :

org.hibernate.MappingException: Unknown entity: 
com.foreach.ex.mappingexception.persistence.model.Foo
at o.h.i.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:1141)

Теперь у этой проблемы есть два решения — два способа сообщить LocalSessionFactoryBean о классе сущностей Foo .

Мы можем указать, в каких пакетах искать классы сущностей в пути к классам:

sessionFactory.setPackagesToScan(
new String[] { "com.foreach.ex.mappingexception.persistence.model" });

Или мы можем просто зарегистрировать классы сущностей непосредственно в фабрике сеансов:

sessionFactory.setAnnotatedClasses(new Class[] { Foo.class });

С любой из этих дополнительных строк конфигурации тест теперь будет выполняться правильно и будет пройден.

4. MappingException с Hibernate

Давайте теперь посмотрим на ошибку при использовании только Hibernate:

public class Cause4MappingExceptionIntegrationTest {

@Test
public void givenEntityIsPersisted_thenException() throws IOException {
SessionFactory sessionFactory = configureSessionFactory();

Session session = sessionFactory.openSession();
session.beginTransaction();
session.saveOrUpdate(new Foo());
session.getTransaction().commit();
}

private SessionFactory configureSessionFactory() throws IOException {
Configuration configuration = new Configuration();
InputStream inputStream = this.getClass().getClassLoader().
getResourceAsStream("hibernate-mysql.properties");
Properties hibernateProperties = new Properties();
hibernateProperties.load(inputStream);
configuration.setProperties(hibernateProperties);

// configuration.addAnnotatedClass(Foo.class);

ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().
applySettings(configuration.getProperties()).buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
}

Файл hibernate-mysql.properties содержит свойства конфигурации Hibernate :

hibernate.connection.username=tutorialuser
hibernate.connection.password=tutorialmy5ql
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.connection.url=jdbc:mysql://localhost:3306/spring_hibernate4_exceptions
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create

Запуск этого теста приведет к такому же исключению сопоставления:

org.hibernate.MappingException: 
Unknown entity: com.foreach.ex.mappingexception.persistence.model.Foo
at o.h.i.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:1141)

Как, наверное, уже понятно из примера выше, чего не хватает в конфигурации, так это добавления метаданных класса сущности — Foo — в конфигурацию :

configuration.addAnnotatedClass(Foo.class);

Это исправляет тест, который теперь может сохранять сущность Foo.

5. Вывод

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

Реализацию всех примеров исключений можно найти в проекте github — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.