Comments 24
Делал такой же изврат на Codedom + NHibernate. Из опыта уверен, что означенная проблема должна решаться как-то по другому )
1) каким образом происходим изменение Типов? к примеру удаление и удаление полей на лету? интересен момент работы с Hibernate в этот момент
2) получается каждый раз при поднятии сервера, он компилит классы типов заново?
2) получается каждый раз при поднятии сервера, он компилит классы типов заново?
1) При изменении структуры типов нужно заново строить классы (причём — в новом класс-лоадере, разумеется). Изменить класс на лету нельзя — можно только загрузить заново.
И после этого заново строится SessionFactory / EntityManagerFactory с новыми классами.
2) Да, при поднятии сервера и при изменении конфигурации. Но не надо боятся слова «компилит» — это происходит намного быстрее чем компилирование кода в Javac. Фактически класс загружается не с диска, а из памяти, так как код не компилирует, а практически записывает байт-код в массив.
И после этого заново строится SessionFactory / EntityManagerFactory с новыми классами.
2) Да, при поднятии сервера и при изменении конфигурации. Но не надо боятся слова «компилит» — это происходит намного быстрее чем компилирование кода в Javac. Фактически класс загружается не с диска, а из памяти, так как код не компилирует, а практически записывает байт-код в массив.
1) > И после этого заново строится SessionFactory / EntityManagerFactory с новыми классами
это узкое место, хотя с учетом того что классы типы изменяются очень редко, это не критично
2) необязательно использовать javac, можно заюзать ToolProvider.getSystemJavaCompiler()
это узкое место, хотя с учетом того что классы типы изменяются очень редко, это не критично
2) необязательно использовать javac, можно заюзать ToolProvider.getSystemJavaCompiler()
2) В том то и фишка, что компилятор вообще не используется, и это не отнимает время процессора. Какой бы JavaCompiler или EclipseJavaCompiler не использовать — это будет медленно, так как надо разобрать грамматику, найти зависимые класс, сгенерировать код и т.д. А тут — фактически двоичный код пишется, разве что байт-код, а не исполняемый машинный.
Спасибо за интересную и исчерпывающую статью. В текущей работе я, наверное, не буду стараться добавлять универсальности. Но на будущее очень полезно. Рад, что на хабре появляются статьи по java.
Можно ли обращаться к этим классам из обычных исходников? Если нет, то можно было бы использовать DynamicMap в Hibernate.
опишите в двух словах что даст DynamicMap? когда-то пытался его прикрутить, но чего-то не очень получилось, может примерчик скинете достойный?
docs.jboss.org/hibernate/core/3.3/reference/en/html/persistent-classes.html#persistent-classes-dynamicmodels
Если в 2 словах, то вместо POJO используется HashMap. Конфигурация задается в XML. Из минусов можно отметить гемор в написании бизнес логики (нет проверки имен и типов свойств на этапе компиляции).
Если в 2 словах, то вместо POJO используется HashMap. Конфигурация задается в XML. Из минусов можно отметить гемор в написании бизнес логики (нет проверки имен и типов свойств на этапе компиляции).
Для обращении из обычных исходников делается так:
вариант а:
— обращаемся, как и раньше, по ((TextField)object.getField(name)).getValue()
вариант б:
— создаём интерфейс:
в описании ComplexType добавляем интерфейс:
Теперь после загрузки можно кастовать объект к этому интерфейсу и использовать поля:
вариант а:
— обращаемся, как и раньше, по ((TextField)object.getField(name)).getValue()
вариант б:
— создаём интерфейс:
public interface ArticleContent { public String getContent(); public void setContent(String value); }
в описании ComplexType добавляем интерфейс:
complexType.getInterfaces().add(ArticleContent.class);
Теперь после загрузки можно кастовать объект к этому интерфейсу и использовать поля:
ArticleContent content = (ArticleContent) loaded; content.getContent();
Я не очень понял суть решения, но не проще ли генерировать исходные ява-файлы, а не байт-код? И да, кодогенераци в данном примере имхо изврат и неправильный подход. Кодогенерацией как правило, пользуются, чтобы автоматизировать процес создания кода методом копипаста, что изначально неправильно.
И тем более в ява кодогенерация неоправданна, так как там код загружается не при каждом запросе как в PHP апри старте сервера. Вы можете сгенерировать лббые классы динамически.
И тем более в ява кодогенерация неоправданна, так как там код загружается не при каждом запросе как в PHP апри старте сервера. Вы можете сгенерировать лббые классы динамически.
Нет, это не то. Генерировать классы динамически — значит создавать их в памяти, добавляя свойства и методы, а не байт код или исходный код.
Интересно послушать как, не добавляя байт-код или исходный-код, вы собираетесь добавлять методы. Что же они делать-то будут?
Может быть, вы имеете ввиду Proxy + interfaces + InvokationHandler, когда коду передаётся имя метода и он решает, как этот метод должен работать? Это тоже вариант, но намного более медленный.
Может быть, вы имеете ввиду Proxy + interfaces + InvokationHandler, когда коду передаётся имя метода и он решает, как этот метод должен работать? Это тоже вариант, но намного более медленный.
Имхо у подхода есть один существенный недостаток: хибернейт при изменении модели не умеет делать ALTER таблицы, а вместо этого делает DELETE и затем CREATE таблицы. А значит что пропадает полностью все текущее состояние.
Если ты научил хибернейт менять схему, то дай знать пожалуйста.
Если ты научил хибернейт менять схему, то дай знать пожалуйста.
да ну, у меня он делает ALTER при расширении полей типа, а вот при уменьшении поля таблицы остаются, нужно руками удалять
В общем случае этого нельзя добиться даже теоретически, так как неизвестно: переименовал ты колонку или удалил старую и добавил новую. Для того, чтобы заработало автоматическое обновление схемы нужно в некотором виде хранить историю изменений классов объектов с данными. Например, в аннотации к свойству указывать предыдущие имена.
а если операции переименовывания или удаления делать через спец методы, тогда можно добится
Поподробнее можно? ссылочку какую-нибудь подкиньте, пожалуйста.
подробнее в 2-х словах: переименование полей делаете через свой спец метод, который удалит старое поле в классе и создаст новое (после чего Хибернейт сделает ALTER) + этот же метод либо удалит старое поле в таблице, либо сначала скопирует данные в новое поле а только потом удалит старое. Вообщем это надо руками делать, но это реально реализуемо, мы сделали такой механизм у себя в сервисе структур
У меня делает Alter, что я делаю не так? :)
А не лучше ли, кстати, использовать groovy для динамической метамодели? Какие мысли по этому поводу? По идее значительно проще: www.jroller.com/melix/entry/dynamic_database_models_with_groovy
Sign up to leave a comment.
Java-ассемблер, мета-программирование и JPA