Spring/Hibernate 对实体使用注释和 hbm 混合时无法初始化 EntityManager

Spring/Hibernate fails to initialize the EntityManager when using mix of annotations and hbm for entities

我有一个 Spring/Hibernate 项目,其中包含使用 hbm 和注释定义的实体。

当我尝试部署项目时,我收到以下错误消息:

Caused by: org.hibernate.MappingException: Following super classes referenced in extends not found: hibernate.examples.model.Task
    at org.hibernate.cfg.Configuration.processExtendsQueue(Configuration.java:1768) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1690) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1426) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.perform(EntityManagerFactoryBuilderImpl.java:857) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.perform(EntityManagerFactoryBuilderImpl.java:850) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849) ~[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]
    ....................

我必须继续使用两者的原因是因为一些代码是遗留的,我目前无法触及。我们必须开始使用注释来创建任何向前发展的新实体。

这就是我将两种映射注册到配置中的方式:

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("hibernate.examples.model", "models");
        em.setMappingResources("Task.hbm.xml");
        em.setMappingResources("HealthTask.hbm.xml");

        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibernateProperties());
        return em;
    }

setPackagesToScan 方法扫描所有由注释标记的实体,setMappingResources 应该处理 hbm 文件。

当我注释掉 em.setMappingResources..... 时,项目将顺利部署。

此外,需要注意的奇怪部分是,当我 运行 它作为一个独立的应用程序时,即使用 public static void main(String[] args) 我在使用这两种映射时都没有任何问题。所有实体都已注册并创建了架构。

这是我 运行 项目的方式:

public class ConceptRunner {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

        ctx.register(HibernateConfiguration.class);
        ctx.refresh();

        System.exit(0);

    }

}

但是一旦我部署项目,它就无法注册 hbm 文件。

这是我的 hbm 文件:

Task.hbm.xml

<hibernate-mapping>
    <class name="hibernate.examples.model.Task" table="TASKS" abstract="true">
        <id name="id" type="java.lang.Long">
            <column name="ID" precision="22" scale="0"/>
            <generator class="identity"/>
        </id>
        <discriminator column="TYPE" type="string"/>
        <property name="type" type="java.lang.String" insert="false" update="false">
            <column name="TYPE" length="10"/>
        </property>
        <property name="name" type="java.lang.String">
            <column name="NAME" length="50"/>
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" length="250"/>
        </property>
    </class>
</hibernate-mapping>

健康Task.hbm.xml

<hibernate-mapping>
    <subclass name="hibernate.examples.model.HealthTask"
              extends="hibernate.examples.model.Task" discriminator-value="HEALTH">
        <property name="requestServed" type="java.lang.Long">
            <column name="REQUEST_SERVED"/>
        </property>
        <property name="requestFailed" type="java.lang.Long">
            <column name="REQUEST_FAILED"/>
        </property>
        <property name="totalRequest" type="java.lang.Long">
            <column name="TOTAL_REQUEST"/>
        </property>
    </subclass>
</hibernate-mapping>

如果您想从我这里得到任何其他信息,请告诉我..

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan("hibernate.examples.model", "models");
    em.setMappingResources("Task.hbm.xml");
    em.setMappingResources("HealthTask.hbm.xml");

    final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    em.setJpaProperties(hibernateProperties());
    return em;
}

因为 setMappingResources 是一个 setter 每次调用它都会替换当前的资源集。当您在代码中调用它两次时,只会保留最后一个(HealthTask.hbm.xmlTask.hbm.xml 将被忽略)。

如果你看一下 LocalContainerEntityManagerFactoryBeansetMappingResources,你会注意到它需要一个 String... 作为参数(准确地说是可变参数)。

所以不要调用它两次,而是使用 2 个参数调用它一次。

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPackagesToScan("hibernate.examples.model", "models");
    em.setMappingResources("Task.hbm.xml", "HealthTask.hbm.xml");

    final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    em.setJpaProperties(hibernateProperties());
    return em;
}