论坛首页 Java版 Hibernate

介绍Hibernate中的NamingStrategy

浏览 10496 次
该帖已经被评为精华帖
作者 正文
时间: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的用处, 看看它是怎么修理这个问题的, 代码如下:

[code:1]
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();
}

}
[/code:1]

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

这样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里试了一下
[code:1]<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"/>[/code:1]

在这个 <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方法:
[code:1]
protected Configuration newConfiguration() throws HibernateException {
Configuration config = new Configuration();
config.setNamingStrategy(UnderscoreNamingStrategy.INSTANCE);
return config;
}
[/code:1]
   
0 请登录后投票
时间:2005-01-25
明白了 谢谢!
   
0 请登录后投票
时间:2005-03-14
可以在xdoclet生成.hbm.xml时也使用NamingStrategy嘛?不知道各位如果用了NamingStrategy后,*.hbm.xml怎么生成,特别是[code:1]<property
name="postalCode"
type="java.lang.String"
update="true"
column="postalCode"
insert="true"
length="45"
/>[/code:1]
类似上面这种情况,数据库中的列名其实是postal_code。
   
0 请登录后投票
论坛首页 Java版 Hibernate

跳转论坛:
JavaEye推荐