Hibernate(至截稿時最新版本為4.1.3.Final)自動建表的表字段順序總是隨機的,之前我們總是自己寫語句建好表,再使用Hibernate進行增刪改查。始終是有點不方便。
最近看了下源碼,發現很多地方都是使用LinkedHashMap或者是List來傳輸Entity里面的fields,覺得Hibernate應該是考慮到使用Entity里面定義的fields的順序來實現建表語句里的表字段順序的。
於是一步步跟蹤下去,終於在一個地方發現了一個問題:org.hibernate.cfg.PropertyContainer在取fields的時候是使用TreeMap來保存的,於是試着改了下,將這個里面的所有TreeMap改成了LinkedHashMap,編譯通過,打包,測試。
終於,我們期待已久的結果出來了:建表語句里面的字段順序和Entity里面的fields的順序一致了。
以下附上源碼和修改后的代碼:
源碼:
private final TreeMap<String, XProperty> fieldAccessMap;
private final TreeMap<String, XProperty> propertyAccessMap;
private TreeMap<String, XProperty> initProperties(AccessType access) {
if ( !( AccessType.PROPERTY.equals( access ) || AccessType.FIELD.equals( access ) ) ) {
throw new IllegalArgumentException( "Access type has to be AccessType.FIELD or AccessType.Property" );
}
// 其實通過以下注釋也可以發現是Hibernate自己的一個失誤
//order so that property are used in the same order when binding native query
TreeMap<String, XProperty> propertiesMap = new TreeMap<String, XProperty>();
List<XProperty> properties = xClass.getDeclaredProperties( access.getType() );
for ( XProperty property : properties ) {
if ( mustBeSkipped( property ) ) {
continue;
}
propertiesMap.put( property.getName(), property );
}
return propertiesMap;
}
修改后的代碼
private final LinkedHashMap<String, XProperty> fieldAccessMap;
private final LinkedHashMap<String, XProperty> propertyAccessMap;
private LinkedHashMap<String, XProperty> initProperties(AccessType access) {
if ( !( AccessType.PROPERTY.equals( access ) || AccessType.FIELD.equals( access ) ) ) {
throw new IllegalArgumentException( "Access type has to be AccessType.FIELD or AccessType.Property" );
}
//order so that property are used in the same order when binding native query
LinkedHashMap<String, XProperty> propertiesMap = new LinkedHashMap<String, XProperty>();
List<XProperty> properties = xClass.getDeclaredProperties( access.getType() );
for ( XProperty property : properties ) {
if ( mustBeSkipped( property ) ) {
continue;
}
propertiesMap.put( property.getName(), property );
}
return propertiesMap;
}
PS:通過以下代碼可以測試建表時的語句:
public static void main(String[] args) {
Configuration cfg = new Configuration().configure();
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
}