jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
Signup
Mod4j: Modeling for Java using Domain Specific Languages
  • Mod4j: Modeling for Java using Domain Specific Languages
  • MODFORJ-117

Flexible ddl generation

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Improvement Improvement
  • Status: Resolved Resolved
  • Priority: Blocker Blocker
  • Resolution: Fixed
  • Affects Version/s: 1.0.1
  • Fix Version/s: 1.1.0
  • Component/s: DSL for Business Domain
  • Labels:
    None
  • Environment:
    all
  • Number of attachments :
    0

Description

Currently, the table name is generated out of the classname + "_TABLE". This convention can not be overridden, and since my DBA does not accept this convetion, I can not use Mod4J as I would like to. I have to change the hbm.xml files manually which prevents re-generation after changing the model.

It is highly desireable to make the class -> ddl generation flexible, for examaple using the NamingStrategy of Hibernate.

Issue Links

is related to

Bug - A problem which impairs or prevents the functions of the product. MODFORJ-116 Spring overriding-mechanism doesn't work when overriding the tra-transactionmanager with another transactionmanager in the /service/applicationContext.xml

  • Major - Major loss of function.
  • Resolved - A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Vincent Lussenburg added a comment - 20/Jul/09 9:34 AM

I'd like to add something to this issue. I also regard it as Blocking, so I spent some time creating a NamingStrategy since I want to use an existing datamodel.

This all went a LOT easier then I expected.

First, I created a NamingStrategy based on this blog, extending the ImprovedNamingStrategy (which almost matches my datamodel wishes).

    /**
     * {@inheritDoc}
     */
    @Override
    public String tableName(final String tableName) {
        final String renamedTableName;

        // FIXME remove once mod4j default is no longer _TABLE
        if (tableName.endsWith(MOD4J_DEFAULT_TABLE_SUFFIX)) {
            renamedTableName = tableName.replaceAll(MOD4J_DEFAULT_TABLE_SUFFIX, "");
        } else {
            renamedTableName = tableName;
        }

        return super.tableName(renamedTableName);
    }

This effectively removes the _TABLE, which is just one example of course. In my case, the datamodel contains some abbreviations (_ind instead of _indication for example) that I also put in there. Next, I modified the applicationContextBase.xml (which gets overridden next time I touch a model of course).

    <bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" id="sessionFactory">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
        <property name="namingStrategy" ref="namingStrategy" />
        <property name="mappingResources">
(....)
    <bean id="namingStrategy" class="nl.x.y.data.hibernate.mapping.JobportalNamingStrategy" />

A very quick fix here would be to introduce a property allowing the classname of a namingStrategy to be specified which is default set to the Hibernate DefaultNamingStrategy (or rather the ImprovedNamingStrategy, cause CamelCase in database tables and columns is ugly! ). This allows a great deal more flexibility.

Also, in the hbm.xml, the table or column names should no longer be generated (since it's not needed, configuration by exception). This might also fix the bug MODFORJ-124!

Since this is a really small fix solving a really large issue I think it should be done ASAP

Note: In my opinion, this doesn't mean the hbm.xml shouldn't be made editable in some way in the future, since NamingStratregies only apply to rules that apply to the whole datamodel. It's not uncommon to have one or a few columns break the normal rules, because of history, other applications using the tables, etc etc. You don't want to hardcode that kind of stuff in the NamingStrategy, but rather specify the column name in the hbm.xml (configuration by exception).

Show
Vincent Lussenburg added a comment - 20/Jul/09 9:34 AM I'd like to add something to this issue. I also regard it as Blocking, so I spent some time creating a NamingStrategy since I want to use an existing datamodel. This all went a LOT easier then I expected. First, I created a NamingStrategy based on this blog , extending the ImprovedNamingStrategy (which almost matches my datamodel wishes). /** * {@inheritDoc} */ @Override public String tableName( final String tableName) { final String renamedTableName; // FIXME remove once mod4j default is no longer _TABLE if (tableName.endsWith(MOD4J_DEFAULT_TABLE_SUFFIX)) { renamedTableName = tableName.replaceAll(MOD4J_DEFAULT_TABLE_SUFFIX, ""); } else { renamedTableName = tableName; } return super .tableName(renamedTableName); } This effectively removes the _TABLE, which is just one example of course. In my case, the datamodel contains some abbreviations (_ind instead of _indication for example) that I also put in there. Next, I modified the applicationContextBase.xml (which gets overridden next time I touch a model of course). <bean class= "org.springframework.orm.hibernate3.LocalSessionFactoryBean" id= "sessionFactory" > <property name= "dataSource" > <ref local= "dataSource" /> </property> <property name= "namingStrategy" ref= "namingStrategy" /> <property name= "mappingResources" > (....) <bean id= "namingStrategy" class= "nl.x.y.data.hibernate.mapping.JobportalNamingStrategy" /> A very quick fix here would be to introduce a property allowing the classname of a namingStrategy to be specified which is default set to the Hibernate DefaultNamingStrategy (or rather the ImprovedNamingStrategy, cause CamelCase in database tables and columns is ugly! ). This allows a great deal more flexibility. Also, in the hbm.xml, the table or column names should no longer be generated (since it's not needed, configuration by exception). This might also fix the bug MODFORJ-124 ! Since this is a really small fix solving a really large issue I think it should be done ASAP Note: In my opinion, this doesn't mean the hbm.xml shouldn't be made editable in some way in the future, since NamingStratregies only apply to rules that apply to the whole datamodel. It's not uncommon to have one or a few columns break the normal rules, because of history, other applications using the tables, etc etc. You don't want to hardcode that kind of stuff in the NamingStrategy, but rather specify the column name in the hbm.xml (configuration by exception).
Hide
Permalink
Vincent Lussenburg added a comment - 20/Jul/09 2:15 PM

Or... modify applicationContextBase.xml (note the abtract="true"!):

    <!-- abstract bean definition for the hibernate wiring -->
    <bean id="sessionFactoryBase" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" abstract="true">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <!-- resources to locations so we can use wildcards -->
        <property name="mappingLocations">
            <list>
                <value>classpath*:nl/x/y/domain/*.hbm.xml
                </value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

And modify applicationContext.xml

    <!-- overridden hibernate wiring, note, it does not require class definition, since it inherits from it's parent -->
    <bean id="sessionFactory" parent="sessionFactoryBase">
      <property name="namingStrategy" ref="namingStrategy" />
    </bean>

What's that smell...? It is the generation gap pattern?

Show
Vincent Lussenburg added a comment - 20/Jul/09 2:15 PM Or... modify applicationContextBase.xml (note the abtract="true"!): <!-- abstract bean definition for the hibernate wiring --> <bean id= "sessionFactoryBase" class= "org.springframework.orm.hibernate3.LocalSessionFactoryBean" abstract = " true " > <property name= "dataSource" > <ref local= "dataSource" /> </property> <!-- resources to locations so we can use wildcards --> <property name= "mappingLocations" > <list> <value>classpath*:nl/x/y/domain/*.hbm.xml </value> </list> </property> <property name= "hibernateProperties" > <props> <prop key= "hibernate.dialect" >${hibernate.dialect}</prop> <prop key= "hibernate.show_sql" > true </prop> <prop key= "hibernate.format_sql" > true </prop> <prop key= "hibernate.cache.use_second_level_cache" > true </prop> <prop key= "hibernate.cache.use_query_cache" > true </prop> <prop key= "hibernate.cache.provider_class" >org.hibernate.cache.EhCacheProvider</prop> <prop key= "hibernate.hbm2ddl.auto" >update</prop> </props> </property> </bean> And modify applicationContext.xml <!-- overridden hibernate wiring, note, it does not require class definition, since it inherits from it's parent --> <bean id= "sessionFactory" parent= "sessionFactoryBase" > <property name= "namingStrategy" ref= "namingStrategy" /> </bean> What's that smell...? It is the generation gap pattern?
Hide
Permalink
Jos Warmer added a comment - 23/Jul/09 8:00 AM

Is the "abstract=true" neccesary. You can already use the applicationContext.xml file as you point out.

Show
Jos Warmer added a comment - 23/Jul/09 8:00 AM Is the "abstract=true" neccesary. You can already use the applicationContext.xml file as you point out.
Hide
Permalink
Vincent Lussenburg added a comment - 24/Jul/09 3:28 AM

In this case it is because the id's of the bean id differ (sessionFactory vs sessionFactoryBase). This difference in id can't be avoided in an abstract/concrete setup. If I don't (I tried this) I end up booting two sessionFactories, one with namingStrategy and one without.

Another option is to put both the abstract parent (sessionFactoryBase) and the concrete bean (sessionFactory) in the applicationContextBase.xml. Like so:

    <!-- abstract bean definition for the hibernate wiring -->
    <bean id="sessionFactoryBase" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" abstract="true">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <!-- resources to locations so we can use wildcards -->
        <property name="mappingLocations">
            <list>
                <value>classpath*:nl/x/y/domain/*.hbm.xml
                </value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!-- concrete bean, it does not require class definition, since it inherits from it's parent -->
    <bean id="sessionFactory" parent="sessionFactoryBase" />

Say I want to add a namingStrategy, I can still override the concrete sessionFactory (by defining a bean with an identical id) but still benefit from the configuration done in the parent. This way, my applicationContext.xml is initially empty (like it is now).

These options aren't the only ones. If you really like Spring magic, you can also set autowire byType and when I define a bean with type NamingStrategy it will automagically injected into the sessionFactory. I do like Spring magic, but I don't like mixing xml-configuration and automagical autowiring

As always, it's a trade-off. I would like that even a Spring no-no could spot that a base is abstract and never will be instantiated without a concrete definition, that's defined in the separate extension point (very much like how the domain classes are generated). In the case of overriden a bean id, you have to know that Spring allows this kind of behaviour. The other side of the coin is that the extension points are no longer empty by default (much like the domain classes again). Also, this is only needed when a bean definition is especially long and volatile.

Tough one, lucky me that I don't have to make the decision

Show
Vincent Lussenburg added a comment - 24/Jul/09 3:28 AM In this case it is because the id's of the bean id differ (sessionFactory vs sessionFactoryBase). This difference in id can't be avoided in an abstract/concrete setup. If I don't (I tried this) I end up booting two sessionFactories, one with namingStrategy and one without. Another option is to put both the abstract parent (sessionFactoryBase) and the concrete bean (sessionFactory) in the applicationContextBase.xml. Like so: <!-- abstract bean definition for the hibernate wiring --> <bean id= "sessionFactoryBase" class= "org.springframework.orm.hibernate3.LocalSessionFactoryBean" abstract = " true " > <property name= "dataSource" > <ref local= "dataSource" /> </property> <!-- resources to locations so we can use wildcards --> <property name= "mappingLocations" > <list> <value>classpath*:nl/x/y/domain/*.hbm.xml </value> </list> </property> <property name= "hibernateProperties" > <props> <prop key= "hibernate.dialect" >${hibernate.dialect}</prop> <prop key= "hibernate.show_sql" > true </prop> <prop key= "hibernate.format_sql" > true </prop> <prop key= "hibernate.cache.use_second_level_cache" > true </prop> <prop key= "hibernate.cache.use_query_cache" > true </prop> <prop key= "hibernate.cache.provider_class" >org.hibernate.cache.EhCacheProvider</prop> <prop key= "hibernate.hbm2ddl.auto" >update</prop> </props> </property> </bean> <!-- concrete bean, it does not require class definition, since it inherits from it's parent --> <bean id= "sessionFactory" parent= "sessionFactoryBase" /> Say I want to add a namingStrategy, I can still override the concrete sessionFactory (by defining a bean with an identical id) but still benefit from the configuration done in the parent. This way, my applicationContext.xml is initially empty (like it is now). These options aren't the only ones. If you really like Spring magic, you can also set autowire byType and when I define a bean with type NamingStrategy it will automagically injected into the sessionFactory. I do like Spring magic, but I don't like mixing xml-configuration and automagical autowiring As always, it's a trade-off. I would like that even a Spring no-no could spot that a base is abstract and never will be instantiated without a concrete definition, that's defined in the separate extension point (very much like how the domain classes are generated). In the case of overriden a bean id, you have to know that Spring allows this kind of behaviour. The other side of the coin is that the extension points are no longer empty by default (much like the domain classes again). Also, this is only needed when a bean definition is especially long and volatile. Tough one, lucky me that I don't have to make the decision
Hide
Permalink
Eric Jan Malotaux added a comment - 10/Aug/09 1:48 PM

Now that the definition of the Hibernate session factory is factored out into its own Spring configuration file, this issue is already half solved. The other half will be a custom Mod4jNamingStrategy that suffixes all table names with '_TABLE'. The 'table=...' attributes can then go away from the mapping files.

Show
Eric Jan Malotaux added a comment - 10/Aug/09 1:48 PM Now that the definition of the Hibernate session factory is factored out into its own Spring configuration file, this issue is already half solved. The other half will be a custom Mod4jNamingStrategy that suffixes all table names with '_TABLE'. The 'table=...' attributes can then go away from the mapping files.
Hide
Permalink
Eric Jan Malotaux added a comment - 14/Aug/09 11:30 AM

Table and column names are mostly eliminated from the mapping files. Only foreign key column names I have not been able to find a way to eliminate. The '_TABLE' suffix is added by a specially made Mod4jNamingStrategy to avoid accidentally generating table names that conflict with SQL reserved words, like "order" for instance.

Show
Eric Jan Malotaux added a comment - 14/Aug/09 11:30 AM Table and column names are mostly eliminated from the mapping files. Only foreign key column names I have not been able to find a way to eliminate. The '_TABLE' suffix is added by a specially made Mod4jNamingStrategy to avoid accidentally generating table names that conflict with SQL reserved words, like "order" for instance.

People

  • Assignee:
    Eric Jan Malotaux
    Reporter:
    Eelco aartsen
Vote (1)
Watch (1)

Dates

  • Created:
    24/May/09 12:55 PM
    Updated:
    22/Oct/09 3:07 AM
    Resolved:
    14/Aug/09 11:30 AM
  • Atlassian JIRA (v5.2.7#850-sha1:b2af0c8)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.