Spring3升级Spring6+Hibernate XML映射报错:courthouseid字段未找到
将老旧Spring 3应用升级至Spring 6(对应Hibernate 6),采用Hibernate XML映射方案,执行HQL查询时遭遇SQLException:Column (courthouseid) not found in any table in the query (or SLV is undefined) on composite-id field。
查询代码:
@SuppressWarnings("unchecked") List<ConfigParameter> configParameterList = (List<ConfigParameter>) hibernateSession.createQuery( "from ConfigParameter configParameter order by category, key, courthouseId, value").list();
ConfigParameter的XML映射:
<hibernate-mapping> <class name="com.gs.jxx.util.ConfigParameter" table="CONFIG_PARMS"> <composite-id name="id" class="com.gs.jxx.util.ConfigParameterKey" mapped="true"> <key-property name="category"/> <key-property name="courthouseId" column="COURT_LOC"/> <key-property name="key"/> </composite-id> <property name="category"/> <property name="courthouseId" column="COURT_LOC"/> <property name="key"/> <property name="value"/> </class> </hibernate-mapping>
courthouseId同时在复合ID和普通属性中配置,映射同一数据库列COURT_LOC,需解决该报错且尽量少改动代码。
原因分析
Hibernate 6对HQL的解析规则比旧版本更严格,当实体属性同时在复合ID和普通字段中重复映射同一列时,直接在HQL中引用属性名(如courthouseId)会导致解析歧义——Hibernate无法明确是引用复合ID内的属性还是普通属性,进而错误地将属性名当作数据库列名去查找,触发"找不到列"的错误。
具体修复方案
方案1:明确引用复合ID内的属性(最小改动)
修改HQL语句,通过复合ID的属性名id来指定courthouseId,消除歧义:
@SuppressWarnings("unchecked") List<ConfigParameter> configParameterList = (List<ConfigParameter>) hibernateSession.createQuery( "from ConfigParameter configParameter order by category, key, id.courthouseId, value").list();
此方案无需修改XML映射,仅调整HQL即可解决问题,符合"尽量少改动"的需求。
方案2:移除冗余的普通属性映射(更规范)
由于复合ID中已经映射了courthouseId到COURT_LOC列,普通属性的重复映射属于冗余配置,Hibernate 6对这类冗余的兼容性更差。可以直接删除XML中的普通属性配置:
<!-- 删除这一行冗余配置 --> <property name="courthouseId" column="COURT_LOC"/>
同时保持方案1中的HQL修改即可,若代码中其他地方未依赖该普通属性,也可直接使用调整后的HQL。
方案3:为普通属性指定别名(备选)
若必须保留重复映射,也可以在HQL中为实体别名加上属性前缀,明确引用普通属性:
@SuppressWarnings("unchecked") List<ConfigParameter> configParameterList = (List<ConfigParameter>) hibernateSession.createQuery( "from ConfigParameter configParameter order by configParameter.category, configParameter.key, configParameter.courthouseId, configParameter.value").list();
不过此方案的稳定性不如方案1,优先推荐方案1。
内容的提问来源于stack exchange,提问作者Thom

