J.Office2有一功能是工做流支持動態表單設計,設計後能夠動態生成數據庫表,而且支持實時查詢(單表及多表都可)。java
因爲J.Office2版本中採用了Hibernate做爲底層的ORM框架,結合Spring框架,Spring容器啓動後,SessionFactory就會被注入到各個業務的Dao層中去。sql
動態建表功能比較容易實現,咱們能夠new一個SessionFactory,而後把它的配置屬性hibernate.hbm2ddl.auto改成update或create,就能夠達到動態修改表結構的效果。數據庫
但若要加入新的hbm或class,須要從新調用SessionFactoryBean來獲取一個全新的SessionFactory,這種方案試過了, 效果並不理想。從新加載,會致使大量的hbm或class文件從新加載,實在有點慢。而且嚴重影響如今注入SessionFactory的Dao。若 Dao採用動態構建SessionFactory,性能又是一問題。而Hibernate沒有提供SessionFactory動態加入hbm或 Class文件。因此實在機關用盡。session
因此最終仍是回到如何擴展Hibernate的SessionFactory類中去了,這想法已經有很多開發人員嘗試過,JE也有一帖子專門討論這個。不 過僅是一Demo,不完善。咱們提供了兩個擴展的類(修改Hibernate中的兩類,使其支持動態加入配置文件,而且能實時查詢。app
咱們僅須要修改兩個類,一個是Configuration,在其裏面加一方法,以下:框架
public void doComplie(){
secondPassCompile();
}eclipse
修改ide
在SessonFactoryImpl類中加入如下方法,(有一些變量值不能修改的,請改成可修改)post
- //add by csx
- public void addNewConfig(Configuration cfg){
- log.info("add NewConfig.....");
-
- Mapping mapping=this.configuration.getMapping();
- this.filters.putAll( cfg.getFilterDefinitions() );
- //Generators:
- Iterator classes = cfg.getClassMappings();
- while ( classes.hasNext() ) {
- PersistentClass model = (PersistentClass) classes.next();
-
- if ( !model.isInherited() ) {
- IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(
- settings.getDialect(),
- settings.getDefaultCatalogName(),
- settings.getDefaultSchemaName(),
- (RootClass) model
- );
- identifierGenerators.put( model.getEntityName(), generator );
- }
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Prepare persisters and link them up with their cache
- // region/access-strategy
-
- String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";
-
- Map entityAccessStrategies = new HashMap();
- Map tmpEntityPersisters=new HashMap();
- Map tmpClassMetadata=new HashMap();
-
-
- this.configuration.getClassMap().putAll(cfg.getClassMap());
- classes = cfg.getClassMappings();
-
- while ( classes.hasNext() ) {
-
- PersistentClass model = (PersistentClass) classes.next();
-
- model.prepareTemporaryTables( mapping, settings.getDialect() );
- String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
-
- // cache region is defined by the root-class in the hierarchy...
- EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName );
- if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
- AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );
- if ( accessType != null ) {
-
- log.trace( "Building cache for entity data [" + model.getEntityName() + "]" );
- EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
- accessStrategy = entityRegion.buildAccessStrategy( accessType );
- entityAccessStrategies.put( cacheRegionName, accessStrategy );
- allCacheRegions.put( cacheRegionName, entityRegion );
- }
- }
- EntityPersister cp = PersisterFactory.createClassPersister( model, accessStrategy, this, cfg.getMapping() );
- tmpEntityPersisters.put( model.getEntityName(), cp );
- tmpClassMetadata.put( model.getEntityName(), cp.getClassMetadata() );
-
- }
-
- //Named Queries:
- namedQueries.putAll(cfg.getNamedQueries());
- namedSqlQueries.putAll( cfg.getNamedSQLQueries() );
- sqlResultSetMappings.putAll(cfg.getSqlResultSetMappings());
- imports.putAll(cfg.getImports());
-
- entityPersisters.putAll(tmpEntityPersisters);
-
- classMetadata.putAll(tmpClassMetadata);
-
- Map tmpEntityToCollectionRoleMap = new HashMap();
- Map tempCollectionPersisters=new HashMap();
-
- this.configuration.getCollectionMap().putAll(cfg.getCollectionMap());
- Iterator collections = cfg.getCollectionMappings();
-
- while ( collections.hasNext() ) {
- Collection model = (Collection) collections.next();
- final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
- final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );
- CollectionRegionAccessStrategy accessStrategy = null;
- if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
- log.trace( "Building cache for collection data [" + model.getRole() + "]" );
- CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
- accessStrategy = collectionRegion.buildAccessStrategy( accessType );
- entityAccessStrategies.put( cacheRegionName, accessStrategy );
- allCacheRegions.put( cacheRegionName, collectionRegion );
- }
- CollectionPersister persister = PersisterFactory.createCollectionPersister(this.getConfiguration(), model, accessStrategy, this) ;
- tempCollectionPersisters.put( model.getRole(), persister.getCollectionMetadata() );
- Type indexType = persister.getIndexType();
- if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
- String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );
- Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );
- if ( roles == null ) {
- roles = new HashSet();
- tmpEntityToCollectionRoleMap.put( entityName, roles );
- }
- roles.add( persister.getRole() );
- }
- Type elementType = persister.getElementType();
- if ( elementType.isAssociationType() && !elementType.isAnyType() ) {
- String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this );
- Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );
- if ( roles == null ) {
- roles = new HashSet();
- tmpEntityToCollectionRoleMap.put( entityName, roles );
- }
- roles.add( persister.getRole() );
- }
-
- }
- //加入新的
- collectionPersisters.putAll(tempCollectionPersisters);
-
- Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();
- while ( itr.hasNext() ) {
- final Map.Entry entry = ( Map.Entry ) itr.next();
- entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );
- }
-
- collectionRolesByEntityParticipant.putAll( tmpEntityToCollectionRoleMap);
-
- // after *all* persisters and named queries are registered
- Iterator iter = tmpEntityPersisters.values().iterator();
- while ( iter.hasNext() ) {
- ( (EntityPersister) iter.next() ).postInstantiate();
- }
- iter = tempCollectionPersisters.values().iterator();
- while ( iter.hasNext() ) {
- ( (CollectionPersister) iter.next() ).postInstantiate();
- }
-
- queryPlanCache=new QueryPlanCache(this);
-
-
- }
咱們動態加入實體,動態可進行查詢,Hibernate提供幾種實體的查詢策略,其中一個是咱們經常使用的pojo,若採用該方法,咱們得加上hbm與 class類或僅是含註解的class至hibernate的SessionFactory,這種方案而且沒有問題,但會遇到當咱們修改表單字段,從新生 成對應的實體時,咱們就會遇到原有的實體class不能在ClassLoader裏卸載。使用的仍是舊的Class,達不到動態查詢的效果。若使用動態的 ClassLoader,代碼將變得很複雜。(嘗試過,代碼相對比較繁雜)性能
還好Hibernate提供了另外一種實體查詢策略,基於Map的動態實體。基於這種方式,咱們配置一個一對多的表,其示例代碼以下:
MainEntity.hbm.xml
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class table="main_entity" entity-name="MainEntity">
- <id name="mainId" column="mainId" type="java.lang.Long">
- <generator class="native"/>
- </id>
- <property name="itemSubject" type="java.lang.String" length="128"/>
- <property name="itemDescp" type="java.lang.String" />
- <property name="createtime" type="java.util.Date" />
- <bag name="subEntitys"
- table="sub_entity"
- lazy="false"
- inverse="true"
- cascade="save-update,delete-orphan"
- >
- <key>
- <column name="mainId"/>
- </key>
- <one-to-many entity-name="SubEntity"/>
- </bag>
- </class>
- </hibernate-mapping>
SubEntity.hbm.xml
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class table="sub_entity" entity-name="SubEntity">
- <id name="subId" column="subId" type="java.lang.Long">
- <generator class="native"/>
- </id>
- <property name="subject" type="java.lang.String" length="128"/>
- <property name="createtime" type="java.util.Date"/>
- <many-to-one name="mainEntity" entity-name="MainEntity" not-null="false" fetch="select">
- <column name="mainId"></column>
- </many-to-one>
- </class>
- </hibernate-mapping>
爲兩實體插入數據後,可動態測試以下:
- public static void main(String[]args){
- ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:app-context.xml");
-
- MyAnnotationSessionFactoryBean sessionFactoryBean=(MyAnnotationSessionFactoryBean)ctx.getBean("&sessionFactory");
-
- SessionFactoryImpl sessionFactoryImpl=(SessionFactoryImpl)sessionFactoryBean.getObject();
-
- Configuration cfg=new Configuration();
- //cfg.configure();
-
- cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/MainEntity.hbm.xml");
- cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/SubEntity.hbm.xml");
- cfg.doComplie();
-
- sessionFactoryImpl.addNewConfig(cfg);
-
- MainEntityDao dao=(MainEntityDao)ctx.getBean("mainEntityDao");
-
- List list=dao.query();
-
- for(int i=0;i<list.size();i++){
- Map map=(Map)list.get(i);
- Iterator it=map.keySet().iterator();
- while(it.hasNext()){
- //String key=(String)it.next();
- Object key=it.next();
- Object val=map.get(key);
- System.out.println("--------------->key:"+key );
- }
- }
-
- Configuration cfg2=new Configuration();
- cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/MainEntity2.hbm.xml");
- cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/SubEntity2.hbm.xml");
- cfg2.doComplie();
- sessionFactoryImpl.addNewConfig(cfg2);
-
- List list2=dao.query();
-
- for(int i=0;i<list2.size();i++){
- Map map=(Map)list2.get(i);
- Iterator it=map.keySet().iterator();
- while(it.hasNext()){
- //String key=(String)it.next();
- Object key=it.next();
- Object val=map.get(key);
- System.out.println("key:"+key );
- }
- }
-
- }
- MainEntity2.hbm.xml與SubEntity2.hbm.xml文件相對原來的文件增長了一些列或刪除了一些列
執行後,能夠實時看到不一樣的結果,而且不會影響現有的dao。