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()));