Hibernate 5 - программное добавление отображения hbm в конфигурацию - именованные запросы не найдены

В процессе миграции старого приложения с JBoss 5.1.0GA на WildFly 13. На предыдущем сервере мы использовали hibernate3, а на WildFly 13 мы пытаемся использовать hibernate 5.

Немного о приложении - оно построено как мультитенантное приложение, поэтому в нем есть таблицы, которые являются общими для всех клиентов, и таблицы, которые зависят от клиента. Эти специфичные для клиента таблицы имеют суффикс с clientId, поэтому они будут читать Document_2, Document_3, ..., Document_n (например).

Общие определения таблиц находятся в архиве.sar, в файле hibernate.cfg.xml.

Для общих отображений таблиц есть еще один класс:

@Singleton
@Startup
public class MyHibernateService
    implements
    DynamicMBean {

    private MBeanServer platformMBeanServer;
    private ObjectName objectName = null;


    @PostConstruct
    public void start() {
        new Configuration().configure().buildSessionFactory();
        this.registerJMX();
    }


    private void registerJMX() {
        try {
            this.objectName = new ObjectName("jboss.jca:service=HibernateFactory,name=HibernateFactory");
            this.platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
            this.platformMBeanServer.registerMBean(this, this.objectName);
        } catch (Exception e) {
            throw new IllegalStateException("Exception during JMX registration :" + e);
        }
    }
....
}

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

Определения / сопоставления специфичных для клиента таблиц основаны на шаблоне. При загрузке приложения мы создаем фабрики сессий, специфичные для каждого клиента. То, как мы это делаем, заключается в том, что мы анализируем сопоставление шаблонов и заменяем некоторые разделы на специфичные для клиента. Шаблон будет читать

<class name="com..DocumentMapping" table="TABLENAME">

где TABLENAME, который будет заменен при загрузке, например, Document_2.

Этот класс SessionFactoryManager, который выполняет все замены, выглядит следующим образом:

if (SessionFactoryManager.LOGGER.isDebugEnabled()) {
    SessionFactoryManager.LOGGER.info("build custom SessionFactory for  datasource: " + databaseConfig);
}

Configuration cfg = new Configuration();

// build all mappings
for (Class c : mappingClasses) {

    try {
        Method m = c.getMethod("getInstance", (Class[])null);
        Helper dao = (Helper)m.invoke(null, (Object[])null);

        String tableName = dao.getTableName(id);

        String mapping = dao.getMappping();

        if (mapping == null) {
            throw new DAOException(DAOException.TYPE.SESSION_FACTORY, "Mapping not available from class: " + c.getName());
        }


        cfg.addXML(mapping);
    } catch (Exception e) {
        throw new DAOException(DAOException.TYPE.SESSION_FACTORY, e);
    }
}

cfg.setProperty("hibernate.dialect", databaseConfig.getDatabaseDialect().getClass().getName());

if (StringTools.isValidString(databaseConfig.getDatabaseJNDI())) {
    cfg.setProperty("hibernate.connection.datasource", databaseConfig.getDatabaseJNDI());
} else {
    cfg.setProperty("hibernate.connection.url", databaseConfig.getDatabaseURL());
    cfg.setProperty("hibernate.connection.driver_class", databaseConfig.getDatabaseDriverClass());
    cfg.setProperty("hibernate.connection.username", databaseConfig.getDatabaseUser());
    cfg.setProperty("hibernate.connection.password", databaseConfig.getDatabasePassword());
}

if (showSQL) {
    cfg.setProperty("hibernate.show_sql", "true");
    cfg.setProperty("hibernate.format_sql", "false");
}

if (operation == OPERATION.RECREATE) {
    cfg.setProperty("hibernate.hbm2ddl.auto", "update");
} else {
    // With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly
    // this is necessary in order to remove client tables if something goes wrong at client creation time
    cfg.setProperty("hibernate.hbm2ddl.auto", "create-drop");
}


SessionFactory sf = cfg.configure().buildSessionFactory();

System.out.println(cfg.getNamedQueries());

Проблема в том, что, хотя я вижу, что cfg.addXML(String xml) устарел, cfg.getNamedQueries() возвращает пустую карту, как если бы отображение не загружалось в конфигурацию.

Весь приведенный выше код отлично работает для hibernate3.

Я также попытался изменить:

SessionFactory sf = cfg.configure().buildSessionFactory();

в

StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder();
builder.applySettings(cfg.getProperties());
MetadataSources metaData = new MetadataSources(builder.build());
Metadata buildMetadata = metaData.buildMetadata(builder.build());
SessionFactory sf = buildMetadata.buildSessionFactory();

но безрезультатно.

Другое изменение, которое я попробовал, было этим:

SessionFactory sf = cfg.configure().buildSessionFactory();

то есть вызывая configure на cfg, после того как он загрузил отображение. В этом случае я получаю исключение повторяющегося запроса, как если бы запросы не были изолированы для фабрики сеансов.

Используемая мной спящая версия - 5.1.14, по умолчанию она поставляется с WildFly 13.

Есть идеи?

1 ответ

Исправлено путем изменения

cfg.addXML(mapping)

в

cfg.addInputStream(new ByteArrayInputStream(mapping.getBytes()));
Другие вопросы по тегам