Hibernateマッピング例外 - 不明なエンティティ

Hibernateマッピングの例外-不明なエンティティ

1. 問題

この記事では、Hibernateと、SpringおよびHibernate環境の両方について、org.hibernate.MappingException: Unknown entityの問題と解決策について説明します。

参考文献:

SpringでHibernate 5をブートストラップする

Hibernate 5とSpringを統合するための迅速かつ実用的なガイド。

Hibernateの@Immutable

Hibernateの@Immutableアノテーションの迅速かつ実用的なガイド

HibernateException:Hibernate 3のスレッドにバインドされたHibernateセッションはありません

「スレッドにバインドされたHibernateセッションがありません」例外がスローされるタイミングとその対処方法を確認します。

2. @Entity注釈がないか無効です

マッピング例外の最も一般的な原因は、単にエンティティクラスmissing the @Entity annotationです。

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;
    }
}

もう1つの可能性は、the wrong type of @Entity annotationが含まれている可能性があることです。

import org.hibernate.annotations.Entity;

@Entity
public class Foo implements Serializable {
    ...

非推奨のorg.hibernate.annotations.Entityは、使用するエンティティのタイプが間違っています–何we need is the javax.persistence.Entity

import javax.persistence.Entity;

@Entity
public class Foo implements Serializable {
    ...

3. MappingException with Spring

configuration of Hibernate in Springには、LocalSessionFactoryBeanを介した注釈スキャンからのSessionFactoryのブートストラップが含まれます。

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

Session Factory Beanのこの単純な構成には重要な要素が欠けており、SessionFactoryを使用しようとするテストは失敗します。

...
@Autowired
private SessionFactory sessionFactory;

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

例外は、予想どおり、MappingException: Unknown entityです。

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

現在、two solutions to this problemがあります–FooエンティティクラスについてLocalSessionFactoryBeanに伝える2つの方法です。

クラスパス内のpackages to search for entity classesを指定できます。

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

または、単にregister the entity classes directlyをSessionFactoryに入れることができます。

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ファイルにはthe Hibernate configuration propertiesが含まれています。

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: org.example.ex.mappingexception.persistence.model.Foo
    at o.h.i.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:1141)

上記の例からすでに明らかなように、構成に欠落しているのはadding the metadata of the entity class – Foo – to the configurationです。

configuration.addAnnotatedClass(Foo.class);

これにより、Fooエンティティを永続化できるテストが修正されます。

5. 結論

この記事では、Unknown entity Mapping Exceptionが発生する理由と、最初にエンティティレベルで、次にSpringとHibernateで、最後にHibernateのみで問題が発生した場合の問題の修正方法を説明しました。

すべての例外の例の実装はthe github projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。