论坛首页 Java企业应用论坛

介绍Hibernate中的NamingStrategy

浏览 30552 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-10-28  
在Java对象里面, 偶们知道一个良好的命名规范会采用大写单词的首字母, 比如订单项这个对象, 偶们会起名为OrderItem, 这样很容易就看出来这个对象是由Order和Item 2个单词组成的, 断词就很容易了, 而属性也是如此, 比如maxPrice, totalPrice等等.

但是如果按照同样的命名规范运到数据库的时候, 由于很多数据库对于表名, 字段名是大小写不敏感的, 所以最常见的策略是加下划线作为断词的依据:
OrderItem -> order_item
maxPrice -> max_price

这样运用Hibernate的时候, 偶们就得手工在mapping文件里面指明:
<class name="OrderItem" table="order_item">
<property name="maxPrice" column="max_price"/>

每个mapping关系都得手工这样写, 是不是很不爽? 现在来介绍一下net.sf.hibernate.cfg.NamingStrategy的用处, 看看它是怎么修理这个问题的, 代码如下:

import net.sf.hibernate.cfg.NamingStrategy;
import net.sf.hibernate.util.StringHelper;

/**
 * An improved naming strategy that prefers embedded underscores to mixed case
 * names, base on DefaultNamingStrategy and ImprovedNamingStrategy
 * 
 */
 
public class UnderscoreNamingStrategy implements NamingStrategy {

    public static final NamingStrategy INSTANCE = new UnderscoreNamingStrategy();;

    protected UnderscoreNamingStrategy(); {
    }

    public String classToTableName(String className); {
        return addUnderscores(StringHelper.unqualify(className););;
    }

    public String propertyToColumnName(String propertyName); {
        return addUnderscores(StringHelper.unqualify(propertyName););;
    }

    public String tableName(String tableName); {
        return tableName;
    }

    public String columnName(String columnName); {
        return columnName;
    }

    public String propertyToTableName(String className, String propertyName); {
        return classToTableName(className); + '_' + propertyToColumnName(propertyName);;
    }

    private String addUnderscores(String name); {
        StringBuffer buf = new StringBuffer(name.replace('.', '_'););;
        for (int i = 1; i < buf.length(); - 1; i++); {
            if ('_' != buf.charAt(i - 1); && Character.isUpperCase(buf.charAt(i);); && !Character.isUpperCase(buf.charAt(i + 1););); {
                buf.insert(i++, '_');;
            }
        }
        return buf.toString();.toLowerCase();;
    }

}


在初始化配置的时候, 把这个NamingStrategy加上:
	    Configuration config = new Configuration();;
	    config.setNamingStrategy(UnderscoreNamingStrategy.INSTANCE);;


这样mapping文件就变得简单多了:

<class name="OrderItem">
<property name="maxPrice"/>

NamingStrategy还可以用在其他方面, 比如有些数据库设计规范统一要求Table前面加上模块名称 (如, 属于Order模块的统一加上ORDER_ ), 比如还有些恶心规范统一要求表名和字段名采用4码缩写 (如, OrderItem -> orde_item, maxPrice -> max_pric), 这些都是NamingStrategy可以解决的脏活累活.
   发表时间:2004-10-30  
谢谢!
楼主的文章让我了解了NamingStrategy
并且专门查看相关的代码
0 请登录后投票
   发表时间:2004-11-15  
我照楼主的方法试了一下,可是发现UnderscoreNamingStrategy.INSTANCE并没有起作用,我的passWord,数据库里是pass_word,运行提示:
Caused by: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]列名 'passWord' 无效。
能否告诉什么原因呢?谢谢!
0 请登录后投票
   发表时间:2004-11-15  
把你的相关代码贴出来......
0 请登录后投票
   发表时间:2005-01-24  
我在spring里试了一下
   
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="mappingResources">
            <list>
                <value>com/wl/dao/hibernate/model/FgglParent.hbm.xml</value>
                <value>com/wl/dao/hibernate/model/FgglChilds.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.Provider</prop>             
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
        <property name="namingStrategy"><ref bean="nameStrategy"/></property>
    </bean> 
    
    <!-- Hibernate NamingStrategy-->
    <bean id="namingStrategy" class="net.sf.hibernate.cfg.ImprovedNamingStrategy"/>


在这个     <bean id="namingStrategy" class="net.sf.hibernate.cfg.ImprovedNamingStrategy"/> 里我实验了用ImprovedNamingStrategy或者楼主的UnderscoreNamingStrategy 都会得到spring 的包错:

org.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'namingStrategy' defined in class path resource [applicationContext.xml]: Validation of bean definition with name failed; nested exception is org.springframework.beans.factory.support.BeanDefinitionValidationException: No public constructor in class [class net.sf.hibernate.cfg.ImprovedNamingStrategy]
org.springframework.beans.factory.support.BeanDefinitionValidationException: No public constructor in class [class net.sf.hibernate.cfg.ImprovedNamingStrategy]
at org.springframework.beans.factory.support.RootBeanDefinition.validate(RootBeanDefinition.java:334)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:210)
at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.registerBeanDefinition(DefaultXmlBeanDefinitionParser.java:188)
at org.springframework.beans.factory.xml.DefaultXmlBeanDefinitionParser.registerBeanDefinitions(DefaultXmlBeanDefinitionParser.java:155)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:161)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:125)
at org.springframework.context.support.AbstractXmlApplicationContext.refreshBeanFactory(AbstractXmlApplicationContext.java:65)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:226)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:58)
at com.wl.test.dao.hibernate.TestDAOToSpring.setUp(TestDAOToSpring.java:15)
at junit.framework.TestCase.runBare(TestCase.java:125)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:186)

----------------------------------------------------------------------
org.springframework.beans.factory.support.BeanDefinitionValidationException: No public constructor in class [class net.sf.hibernate.cfg.ImprovedNamingStrategy]

spring要求要public的构造方法才可以吗?
0 请登录后投票
   发表时间:2005-01-25  
看到ReadOnly提到不爽,想起一个问题。
如果pojo放得比较深,如com.xxx.wap.Book,在写hql的时候要把类的完整package+classname写进去,如"select book.name from com.xxx.wap.Book book",也是N不爽。有没有办法给他一个alias什么的,精简为"select book.name from Book book"?(不过自己感觉希望好像不大。。。。)
0 请登录后投票
   发表时间:2005-01-25  
引用
在写hql的时候要把类的完整package+classname写进去


不需要,只写类的classname就可以了。除非你关掉auto-import,你才需要写packagename
0 请登录后投票
   发表时间:2005-01-25  
doninox 写道
spring要求要public的构造方法才可以吗?

Yes, 你可以写一个Class extends org.springframework.orm.hibernate.LocalSessionFactoryBean

复写newConfiguration方法:
	protected Configuration newConfiguration(); throws HibernateException {
	    Configuration config = new Configuration();;
	    config.setNamingStrategy(UnderscoreNamingStrategy.INSTANCE);;
	    return config;
	}
0 请登录后投票
   发表时间:2005-01-25  
明白了 谢谢!
0 请登录后投票
   发表时间:2005-03-14  
可以在xdoclet生成.hbm.xml时也使用NamingStrategy嘛?不知道各位如果用了NamingStrategy后,*.hbm.xml怎么生成,特别是
<property
            name="postalCode"
            type="java.lang.String"
            update="true"
            column="postalCode"
            insert="true"
            length="45"
        />

类似上面这种情况,数据库中的列名其实是postal_code。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics